script.c 30.1 KB
Newer Older
1 2
/* IDirectMusicScript
 *
3
 * Copyright (C) 2003-2004 Rok Mandeljc
4
 * Copyright (C) 2003-2004 Raphael Junqueira
5
 *
6 7 8 9
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
10 11 12
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
15
 *
16 17 18
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 20
 */

21 22 23 24 25 26 27
#include "config.h"
#include "wine/port.h"

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

28 29
#include "dmscript_private.h"

30
WINE_DEFAULT_DEBUG_CHANNEL(dmscript);
31
WINE_DECLARE_DEBUG_CHANNEL(dmfile);
32

33

34 35 36 37 38
static ULONG WINAPI IDirectMusicScriptImpl_IUnknown_AddRef (LPUNKNOWN iface);
static ULONG WINAPI IDirectMusicScriptImpl_IDirectMusicScript_AddRef (LPDIRECTMUSICSCRIPT iface);
static ULONG WINAPI IDirectMusicScriptImpl_IDirectMusicObject_AddRef (LPDIRECTMUSICOBJECT iface);
static ULONG WINAPI IDirectMusicScriptImpl_IPersistStream_AddRef (LPPERSISTSTREAM iface);

39 40 41 42
/*****************************************************************************
 * IDirectMusicScriptImpl implementation
 */
/* IDirectMusicScriptImpl IUnknown part: */
43
static HRESULT WINAPI IDirectMusicScriptImpl_IUnknown_QueryInterface (LPUNKNOWN iface, REFIID riid, LPVOID *ppobj) {
44 45 46 47
  ICOM_THIS_MULTI(IDirectMusicScriptImpl, UnknownVtbl, iface);
  TRACE("(%p, %s, %p)\n", This, debugstr_dmguid(riid), ppobj);
  
  if (IsEqualIID (riid, &IID_IUnknown)) {
48
    *ppobj = &This->UnknownVtbl;
49 50 51
    IDirectMusicScriptImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
    return S_OK;	
  } else if (IsEqualIID (riid, &IID_IDirectMusicScript)) {
52
    *ppobj = &This->ScriptVtbl;
53 54 55
    IDirectMusicScriptImpl_IDirectMusicScript_AddRef ((LPDIRECTMUSICSCRIPT)&This->ScriptVtbl);
    return S_OK;
  } else if (IsEqualIID (riid, &IID_IDirectMusicObject)) {
56
    *ppobj = &This->ObjectVtbl;
57 58 59
    IDirectMusicScriptImpl_IDirectMusicObject_AddRef ((LPDIRECTMUSICOBJECT)&This->ObjectVtbl);		
    return S_OK;
  } else if (IsEqualIID (riid, &IID_IPersistStream)) {
60
    *ppobj = &This->PersistStreamVtbl;
61 62 63 64 65 66
    IDirectMusicScriptImpl_IPersistStream_AddRef ((LPPERSISTSTREAM)&This->PersistStreamVtbl);		
    return S_OK;
  }
  
  WARN("(%p, %s, %p): not found\n", This, debugstr_dmguid(riid), ppobj);
  return E_NOINTERFACE;
67 68
}

69
static ULONG WINAPI IDirectMusicScriptImpl_IUnknown_AddRef (LPUNKNOWN iface) {
70
  ICOM_THIS_MULTI(IDirectMusicScriptImpl, UnknownVtbl, iface);
71 72
  ULONG ref = InterlockedIncrement(&This->ref);

73
  TRACE("(%p): AddRef from %d\n", This, ref - 1);
74

75 76
  DMSCRIPT_LockModule();

77
  return ref;
78 79
}

80
static ULONG WINAPI IDirectMusicScriptImpl_IUnknown_Release (LPUNKNOWN iface) {
81
  ICOM_THIS_MULTI(IDirectMusicScriptImpl, UnknownVtbl, iface);
82 83
  ULONG ref = InterlockedDecrement(&This->ref);

84
  TRACE("(%p): ReleaseRef to %d\n", This, ref);
85

86
  if (ref == 0) {
87 88 89 90
    HeapFree(GetProcessHeap(), 0, This->pHeader);
    HeapFree(GetProcessHeap(), 0, This->pVersion);
    HeapFree(GetProcessHeap(), 0, This->pwzLanguage);
    HeapFree(GetProcessHeap(), 0, This->pwzSource);
91 92
    HeapFree(GetProcessHeap(), 0, This);
  }
93 94 95

  DMSCRIPT_UnlockModule();
  
96
  return ref;
97 98
}

99
static const IUnknownVtbl DirectMusicScript_Unknown_Vtbl = {
100 101 102
  IDirectMusicScriptImpl_IUnknown_QueryInterface,
  IDirectMusicScriptImpl_IUnknown_AddRef,
  IDirectMusicScriptImpl_IUnknown_Release
103
};
104

105
/* IDirectMusicScriptImpl IDirectMusicScript part: */
106
static HRESULT WINAPI IDirectMusicScriptImpl_IDirectMusicScript_QueryInterface (LPDIRECTMUSICSCRIPT iface, REFIID riid, LPVOID *ppobj) {
107 108
  ICOM_THIS_MULTI(IDirectMusicScriptImpl, ScriptVtbl, iface);
  return IDirectMusicScriptImpl_IUnknown_QueryInterface ((LPUNKNOWN)&This->UnknownVtbl, riid, ppobj);
109 110
}

111
static ULONG WINAPI IDirectMusicScriptImpl_IDirectMusicScript_AddRef (LPDIRECTMUSICSCRIPT iface) {
112 113
  ICOM_THIS_MULTI(IDirectMusicScriptImpl, ScriptVtbl, iface);
  return IDirectMusicScriptImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
114
}
115

116
static ULONG WINAPI IDirectMusicScriptImpl_IDirectMusicScript_Release (LPDIRECTMUSICSCRIPT iface) {
117 118
  ICOM_THIS_MULTI(IDirectMusicScriptImpl, ScriptVtbl, iface);
  return IDirectMusicScriptImpl_IUnknown_Release ((LPUNKNOWN)&This->UnknownVtbl);
119
}
120

121
static HRESULT WINAPI IDirectMusicScriptImpl_IDirectMusicScript_Init (LPDIRECTMUSICSCRIPT iface, IDirectMusicPerformance* pPerformance, DMUS_SCRIPT_ERRORINFO* pErrorInfo) {
122 123 124 125
  ICOM_THIS_MULTI(IDirectMusicScriptImpl, ScriptVtbl, iface);
  FIXME("(%p, %p, %p): stub\n", This, pPerformance, pErrorInfo);
  This->pPerformance = pPerformance;
  return S_OK;
126 127
}

128
static HRESULT WINAPI IDirectMusicScriptImpl_IDirectMusicScript_CallRoutine (LPDIRECTMUSICSCRIPT iface, WCHAR* pwszRoutineName, DMUS_SCRIPT_ERRORINFO* pErrorInfo) {
129 130 131
  ICOM_THIS_MULTI(IDirectMusicScriptImpl, ScriptVtbl, iface);
  FIXME("(%p, %s, %p): stub\n", This, debugstr_w(pwszRoutineName), pErrorInfo);
  /*return E_NOTIMPL;*/
132 133
  return S_OK;
  /*return E_FAIL;*/
134
}
135

136
static HRESULT WINAPI IDirectMusicScriptImpl_IDirectMusicScript_SetVariableVariant (LPDIRECTMUSICSCRIPT iface, WCHAR* pwszVariableName, VARIANT varValue, BOOL fSetRef, DMUS_SCRIPT_ERRORINFO* pErrorInfo) {
137 138 139
  ICOM_THIS_MULTI(IDirectMusicScriptImpl, ScriptVtbl, iface);
  FIXME("(%p, %s, FIXME, %d, %p): stub\n", This, debugstr_w(pwszVariableName),/* varValue,*/ fSetRef, pErrorInfo);
  return S_OK;
140 141
}

142
static HRESULT WINAPI IDirectMusicScriptImpl_IDirectMusicScript_GetVariableVariant (LPDIRECTMUSICSCRIPT iface, WCHAR* pwszVariableName, VARIANT* pvarValue, DMUS_SCRIPT_ERRORINFO* pErrorInfo) {
143 144 145
  ICOM_THIS_MULTI(IDirectMusicScriptImpl, ScriptVtbl, iface);
  FIXME("(%p, %s, %p, %p): stub\n", This, debugstr_w(pwszVariableName), pvarValue, pErrorInfo);
  return S_OK;
146 147
}

148
static HRESULT WINAPI IDirectMusicScriptImpl_IDirectMusicScript_SetVariableNumber (LPDIRECTMUSICSCRIPT iface, WCHAR* pwszVariableName, LONG lValue, DMUS_SCRIPT_ERRORINFO* pErrorInfo) {
149
  ICOM_THIS_MULTI(IDirectMusicScriptImpl, ScriptVtbl, iface);
150
  FIXME("(%p, %s, %i, %p): stub\n", This, debugstr_w(pwszVariableName), lValue, pErrorInfo);
151
  return S_OK;
152 153
}

154
static HRESULT WINAPI IDirectMusicScriptImpl_IDirectMusicScript_GetVariableNumber (LPDIRECTMUSICSCRIPT iface, WCHAR* pwszVariableName, LONG* plValue, DMUS_SCRIPT_ERRORINFO* pErrorInfo) {
155 156 157
  ICOM_THIS_MULTI(IDirectMusicScriptImpl, ScriptVtbl, iface);
  FIXME("(%p, %s, %p, %p): stub\n", This, debugstr_w(pwszVariableName), plValue, pErrorInfo);
  return S_OK;
158 159
}

160
static HRESULT WINAPI IDirectMusicScriptImpl_IDirectMusicScript_SetVariableObject (LPDIRECTMUSICSCRIPT iface, WCHAR* pwszVariableName, IUnknown* punkValue, DMUS_SCRIPT_ERRORINFO* pErrorInfo) {
161 162 163
  ICOM_THIS_MULTI(IDirectMusicScriptImpl, ScriptVtbl, iface);
  FIXME("(%p, %s, %p, %p): stub\n", This, debugstr_w(pwszVariableName), punkValue, pErrorInfo);
  return S_OK;
164 165
}

166
static HRESULT WINAPI IDirectMusicScriptImpl_IDirectMusicScript_GetVariableObject (LPDIRECTMUSICSCRIPT iface, WCHAR* pwszVariableName, REFIID riid, LPVOID* ppv, DMUS_SCRIPT_ERRORINFO* pErrorInfo) {
167 168 169
  ICOM_THIS_MULTI(IDirectMusicScriptImpl, ScriptVtbl, iface);
  FIXME("(%p, %s, %s, %p, %p): stub\n", This, debugstr_w(pwszVariableName), debugstr_dmguid(riid), ppv, pErrorInfo);
  return S_OK;
170 171
}

172
static HRESULT WINAPI IDirectMusicScriptImpl_IDirectMusicScript_EnumRoutine (LPDIRECTMUSICSCRIPT iface, DWORD dwIndex, WCHAR* pwszName) {
173
  ICOM_THIS_MULTI(IDirectMusicScriptImpl, ScriptVtbl, iface);
174
  FIXME("(%p, %d, %p): stub\n", This, dwIndex, pwszName);
175
  return S_OK;
176 177
}

178
static HRESULT WINAPI IDirectMusicScriptImpl_IDirectMusicScript_EnumVariable (LPDIRECTMUSICSCRIPT iface, DWORD dwIndex, WCHAR* pwszName) {
179
  ICOM_THIS_MULTI(IDirectMusicScriptImpl, ScriptVtbl, iface);
180
  FIXME("(%p, %d, %p): stub\n", This, dwIndex, pwszName);
181
  return S_OK;
182 183
}

184
static const IDirectMusicScriptVtbl DirectMusicScript_Script_Vtbl = {
185 186 187 188 189 190 191 192 193 194 195 196 197
  IDirectMusicScriptImpl_IDirectMusicScript_QueryInterface,
  IDirectMusicScriptImpl_IDirectMusicScript_AddRef,
  IDirectMusicScriptImpl_IDirectMusicScript_Release,
  IDirectMusicScriptImpl_IDirectMusicScript_Init,
  IDirectMusicScriptImpl_IDirectMusicScript_CallRoutine,
  IDirectMusicScriptImpl_IDirectMusicScript_SetVariableVariant,
  IDirectMusicScriptImpl_IDirectMusicScript_GetVariableVariant,
  IDirectMusicScriptImpl_IDirectMusicScript_SetVariableNumber,
  IDirectMusicScriptImpl_IDirectMusicScript_GetVariableNumber,
  IDirectMusicScriptImpl_IDirectMusicScript_SetVariableObject,
  IDirectMusicScriptImpl_IDirectMusicScript_GetVariableObject,
  IDirectMusicScriptImpl_IDirectMusicScript_EnumRoutine,
  IDirectMusicScriptImpl_IDirectMusicScript_EnumVariable
198 199
};

200
/* IDirectMusicScriptImpl IDirectMusicObject part: */
201
static HRESULT WINAPI IDirectMusicScriptImpl_IDirectMusicObject_QueryInterface (LPDIRECTMUSICOBJECT iface, REFIID riid, LPVOID *ppobj) {
202 203
  ICOM_THIS_MULTI(IDirectMusicScriptImpl, ObjectVtbl, iface);
  return IDirectMusicScriptImpl_IUnknown_QueryInterface ((LPUNKNOWN)&This->UnknownVtbl, riid, ppobj);
204
}
205

206
static ULONG WINAPI IDirectMusicScriptImpl_IDirectMusicObject_AddRef (LPDIRECTMUSICOBJECT iface) {
207 208
  ICOM_THIS_MULTI(IDirectMusicScriptImpl, ObjectVtbl, iface);
  return IDirectMusicScriptImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
209 210
}

211
static ULONG WINAPI IDirectMusicScriptImpl_IDirectMusicObject_Release (LPDIRECTMUSICOBJECT iface) {
212 213
  ICOM_THIS_MULTI(IDirectMusicScriptImpl, ObjectVtbl, iface);
  return IDirectMusicScriptImpl_IUnknown_Release ((LPUNKNOWN)&This->UnknownVtbl);
214 215
}

216
static HRESULT WINAPI IDirectMusicScriptImpl_IDirectMusicObject_GetDescriptor (LPDIRECTMUSICOBJECT iface, LPDMUS_OBJECTDESC pDesc) {
217 218 219 220 221
  ICOM_THIS_MULTI(IDirectMusicScriptImpl, ObjectVtbl, iface);
  TRACE("(%p, %p)\n", This, pDesc);
  /* I think we shouldn't return pointer here since then values can be changed; it'd be a mess */
  memcpy (pDesc, This->pDesc, This->pDesc->dwSize);
  return S_OK;
222 223
}

224
static HRESULT WINAPI IDirectMusicScriptImpl_IDirectMusicObject_SetDescriptor (LPDIRECTMUSICOBJECT iface, LPDMUS_OBJECTDESC pDesc) {
225 226
  ICOM_THIS_MULTI(IDirectMusicScriptImpl, ObjectVtbl, iface);
  TRACE("(%p, %p): setting descriptor:\n%s\n", This, pDesc, debugstr_DMUS_OBJECTDESC (pDesc));
227

228 229
  /* According to MSDN, we should copy only given values, not whole struct */	
  if (pDesc->dwValidData & DMUS_OBJ_OBJECT)
230
    This->pDesc->guidObject = pDesc->guidObject;
231
  if (pDesc->dwValidData & DMUS_OBJ_CLASS)
232
    This->pDesc->guidClass = pDesc->guidClass;
233
  if (pDesc->dwValidData & DMUS_OBJ_NAME)
234
    lstrcpynW (This->pDesc->wszName, pDesc->wszName, DMUS_MAX_NAME);
235
  if (pDesc->dwValidData & DMUS_OBJ_CATEGORY)
236
    lstrcpynW (This->pDesc->wszCategory, pDesc->wszCategory, DMUS_MAX_CATEGORY);
237
  if (pDesc->dwValidData & DMUS_OBJ_FILENAME)
238
    lstrcpynW (This->pDesc->wszFileName, pDesc->wszFileName, DMUS_MAX_FILENAME);
239
  if (pDesc->dwValidData & DMUS_OBJ_VERSION)
240
    This->pDesc->vVersion = pDesc->vVersion;
241
  if (pDesc->dwValidData & DMUS_OBJ_DATE)
242
    This->pDesc->ftDate = pDesc->ftDate;
243
  if (pDesc->dwValidData & DMUS_OBJ_MEMORY) {
244 245
    This->pDesc->llMemLength = pDesc->llMemLength;
    memcpy (This->pDesc->pbMemData, pDesc->pbMemData, pDesc->llMemLength);
246 247 248 249 250 251 252 253 254 255
  }
  if (pDesc->dwValidData & DMUS_OBJ_STREAM) {
    /* according to MSDN, we copy the stream */
    IStream_Clone (pDesc->pStream, &This->pDesc->pStream);	
  }
  
  /* add new flags */
  This->pDesc->dwValidData |= pDesc->dwValidData;
  
  return S_OK;
256 257
}

258
static HRESULT WINAPI IDirectMusicScriptImpl_IDirectMusicObject_ParseDescriptor (LPDIRECTMUSICOBJECT iface, LPSTREAM pStream, LPDMUS_OBJECTDESC pDesc) {
259 260 261 262
  ICOM_THIS_MULTI(IDirectMusicScriptImpl, ObjectVtbl, iface);
  DMUS_PRIVATE_CHUNK Chunk;
  DWORD StreamSize, StreamCount, ListSize[1], ListCount[1];
  LARGE_INTEGER liMove; /* used when skipping chunks */
263

264
	TRACE("(%p, %p, %p)\n", This, pStream, pDesc);
265

266 267
	/* FIXME: should this be determined from stream? */
	pDesc->dwValidData |= DMUS_OBJ_CLASS;
268 269
	pDesc->guidClass = CLSID_DirectMusicScript;

270
	IStream_Read (pStream, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
271
	TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
272 273 274 275 276 277 278 279 280 281 282
	switch (Chunk.fccID) {	
		case FOURCC_RIFF: {
			IStream_Read (pStream, &Chunk.fccID, sizeof(FOURCC), NULL);				
			TRACE_(dmfile)(": RIFF chunk of type %s", debugstr_fourcc(Chunk.fccID));
			StreamSize = Chunk.dwSize - sizeof(FOURCC);
			StreamCount = 0;
			if (Chunk.fccID == DMUS_FOURCC_SCRIPT_FORM) {
				TRACE_(dmfile)(": script form\n");
				do {
					IStream_Read (pStream, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
					StreamCount += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
283
					TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
					switch (Chunk.fccID) {
						case DMUS_FOURCC_GUID_CHUNK: {
							TRACE_(dmfile)(": GUID chunk\n");
							pDesc->dwValidData |= DMUS_OBJ_OBJECT;
							IStream_Read (pStream, &pDesc->guidObject, Chunk.dwSize, NULL);
							break;
						}
						case DMUS_FOURCC_VERSION_CHUNK: {
							TRACE_(dmfile)(": version chunk\n");
							pDesc->dwValidData |= DMUS_OBJ_VERSION;
							IStream_Read (pStream, &pDesc->vVersion, Chunk.dwSize, NULL);
							break;
						}
						case DMUS_FOURCC_CATEGORY_CHUNK: {
							TRACE_(dmfile)(": category chunk\n");
							pDesc->dwValidData |= DMUS_OBJ_CATEGORY;
							IStream_Read (pStream, pDesc->wszCategory, Chunk.dwSize, NULL);
							break;
						}
						case FOURCC_LIST: {
							IStream_Read (pStream, &Chunk.fccID, sizeof(FOURCC), NULL);				
							TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
							ListSize[0] = Chunk.dwSize - sizeof(FOURCC);
							ListCount[0] = 0;
							switch (Chunk.fccID) {
								/* evil M$ UNFO list, which can (!?) contain INFO elements */
								case DMUS_FOURCC_UNFO_LIST: {
									TRACE_(dmfile)(": UNFO list\n");
									do {
										IStream_Read (pStream, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
										ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
315
										TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
										switch (Chunk.fccID) {
											/* don't ask me why, but M$ puts INFO elements in UNFO list sometimes
                                             (though strings seem to be valid unicode) */
											case mmioFOURCC('I','N','A','M'):
											case DMUS_FOURCC_UNAM_CHUNK: {
												TRACE_(dmfile)(": name chunk\n");
												pDesc->dwValidData |= DMUS_OBJ_NAME;
												IStream_Read (pStream, pDesc->wszName, Chunk.dwSize, NULL);
												break;
											}
											case mmioFOURCC('I','A','R','T'):
											case DMUS_FOURCC_UART_CHUNK: {
												TRACE_(dmfile)(": artist chunk (ignored)\n");
												liMove.QuadPart = Chunk.dwSize;
												IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL);
												break;
											}
											case mmioFOURCC('I','C','O','P'):
											case DMUS_FOURCC_UCOP_CHUNK: {
												TRACE_(dmfile)(": copyright chunk (ignored)\n");
												liMove.QuadPart = Chunk.dwSize;
												IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL);
												break;
											}
											case mmioFOURCC('I','S','B','J'):
											case DMUS_FOURCC_USBJ_CHUNK: {
												TRACE_(dmfile)(": subject chunk (ignored)\n");
												liMove.QuadPart = Chunk.dwSize;
												IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL);
												break;
											}
											case mmioFOURCC('I','C','M','T'):
											case DMUS_FOURCC_UCMT_CHUNK: {
												TRACE_(dmfile)(": comment chunk (ignored)\n");
												liMove.QuadPart = Chunk.dwSize;
												IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL);
												break;
											}
											default: {
355
												TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
356 357 358 359 360
												liMove.QuadPart = Chunk.dwSize;
												IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL);
												break;						
											}
										}
361
										TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]);
362 363 364 365 366 367 368 369 370 371 372 373 374
									} while (ListCount[0] < ListSize[0]);
									break;
								}
								default: {
									TRACE_(dmfile)(": unknown (skipping)\n");
									liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
									IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL);
									break;						
								}
							}
							break;
						}	
						default: {
375
							TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
376 377 378 379 380
							liMove.QuadPart = Chunk.dwSize;
							IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL);
							break;						
						}
					}
381
					TRACE_(dmfile)(": StreamCount[0] = %d < StreamSize[0] = %d\n", StreamCount, StreamSize);
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
				} while (StreamCount < StreamSize);
			} else {
				TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
				liMove.QuadPart = StreamSize;
				IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
				return E_FAIL;
			}
		
			TRACE_(dmfile)(": reading finished\n");
			break;
		}
		default: {
			TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
			liMove.QuadPart = Chunk.dwSize;
			IStream_Seek (pStream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
			return DMUS_E_INVALIDFILE;
		}
	}	
	
401
	TRACE(": returning descriptor:\n%s\n", debugstr_DMUS_OBJECTDESC (pDesc));
402
	
403 404 405
	return S_OK;
}

406
static const IDirectMusicObjectVtbl DirectMusicScript_Object_Vtbl = {
407 408 409 410 411 412
  IDirectMusicScriptImpl_IDirectMusicObject_QueryInterface,
  IDirectMusicScriptImpl_IDirectMusicObject_AddRef,
  IDirectMusicScriptImpl_IDirectMusicObject_Release,
  IDirectMusicScriptImpl_IDirectMusicObject_GetDescriptor,
  IDirectMusicScriptImpl_IDirectMusicObject_SetDescriptor,
  IDirectMusicScriptImpl_IDirectMusicObject_ParseDescriptor
413 414
};

415
/* IDirectMusicScriptImpl IPersistStream part: */
416
static HRESULT WINAPI IDirectMusicScriptImpl_IPersistStream_QueryInterface (LPPERSISTSTREAM iface, REFIID riid, LPVOID *ppobj) {
417 418
  ICOM_THIS_MULTI(IDirectMusicScriptImpl, PersistStreamVtbl, iface);
  return IDirectMusicScriptImpl_IUnknown_QueryInterface ((LPUNKNOWN)&This->UnknownVtbl, riid, ppobj);
419 420
}

421
static ULONG WINAPI IDirectMusicScriptImpl_IPersistStream_AddRef (LPPERSISTSTREAM iface) {
422 423
  ICOM_THIS_MULTI(IDirectMusicScriptImpl, PersistStreamVtbl, iface);
  return IDirectMusicScriptImpl_IUnknown_AddRef ((LPUNKNOWN)&This->UnknownVtbl);
424 425
}

426
static ULONG WINAPI IDirectMusicScriptImpl_IPersistStream_Release (LPPERSISTSTREAM iface) {
427 428
  ICOM_THIS_MULTI(IDirectMusicScriptImpl, PersistStreamVtbl, iface);
  return IDirectMusicScriptImpl_IUnknown_Release ((LPUNKNOWN)&This->UnknownVtbl);
429 430
}

431
static HRESULT WINAPI IDirectMusicScriptImpl_IPersistStream_GetClassID (LPPERSISTSTREAM iface, CLSID* pClassID) {
432 433
  ICOM_THIS_MULTI(IDirectMusicScriptImpl, PersistStreamVtbl, iface);
  TRACE("(%p, %p)\n", This, pClassID);
434
  *pClassID = CLSID_DirectMusicScript;
435
  return S_OK;
436 437
}

438
static HRESULT WINAPI IDirectMusicScriptImpl_IPersistStream_IsDirty (LPPERSISTSTREAM iface) {
439 440 441
  ICOM_THIS_MULTI(IDirectMusicScriptImpl, PersistStreamVtbl, iface);  
  FIXME("(%p): stub, always S_FALSE\n", This);
  return S_FALSE;
442 443
}

444
static HRESULT WINAPI IDirectMusicScriptImpl_IPersistStream_Load (LPPERSISTSTREAM iface, IStream* pStm) {
445 446
	ICOM_THIS_MULTI(IDirectMusicScriptImpl, PersistStreamVtbl, iface);

447 448
	DMUS_PRIVATE_CHUNK Chunk;
	DWORD StreamSize, StreamCount, ListSize[3], ListCount[3];
449
	LARGE_INTEGER liMove; /* used when skipping chunks */
450 451
	LPDIRECTMUSICGETLOADER pGetLoader = NULL;
	LPDIRECTMUSICLOADER pLoader = NULL;
452 453

	FIXME("(%p, %p): Loading not implemented yet\n", This, pStm);
454
	IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
455
	TRACE_(dmfile)(": %s chunk (size = %d)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
456
	switch (Chunk.fccID) {	
457
		case FOURCC_RIFF: {
458 459 460
			IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);				
			TRACE_(dmfile)(": RIFF chunk of type %s", debugstr_fourcc(Chunk.fccID));
			StreamSize = Chunk.dwSize - sizeof(FOURCC);
461
			StreamCount = 0;
462
			switch (Chunk.fccID) {
463 464 465
				case DMUS_FOURCC_SCRIPT_FORM: {
					TRACE_(dmfile)(": script form\n");
					do {
466 467
						IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
						StreamCount += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
468
						TRACE_(dmfile)(": %s chunk (size = %d)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
469 470 471 472 473 474 475 476 477 478 479
						switch (Chunk.fccID) { 
						        case DMUS_FOURCC_SCRIPT_CHUNK: {
							        TRACE_(dmfile)(": script header chunk\n");
								This->pHeader = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, Chunk.dwSize);
								IStream_Read (pStm, This->pHeader, Chunk.dwSize, NULL);
								break;
						        }
						        case DMUS_FOURCC_SCRIPTVERSION_CHUNK: {
							        TRACE_(dmfile)(": script version chunk\n");
								This->pVersion = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, Chunk.dwSize);
								IStream_Read (pStm, This->pVersion, Chunk.dwSize, NULL); 
480
								TRACE_(dmfile)("version: 0x%08x.0x%08x\n", This->pVersion->dwVersionMS, This->pVersion->dwVersionLS);
481 482 483 484 485 486
								break;
						        }
						        case DMUS_FOURCC_SCRIPTLANGUAGE_CHUNK: {
							        TRACE_(dmfile)(": script language chunk\n");
								This->pwzLanguage = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, Chunk.dwSize);
								IStream_Read (pStm, This->pwzLanguage, Chunk.dwSize, NULL); 
487
								TRACE_(dmfile)("using language: %s\n", debugstr_w(This->pwzLanguage));
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504
								break;
						        }
						        case DMUS_FOURCC_SCRIPTSOURCE_CHUNK: {
							        TRACE_(dmfile)(": script source chunk\n");
								This->pwzSource = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, Chunk.dwSize);
								IStream_Read (pStm, This->pwzSource, Chunk.dwSize, NULL); 
								if (TRACE_ON(dmscript)) {
								    int count = WideCharToMultiByte(CP_ACP, 0, This->pwzSource, -1, NULL, 0, NULL, NULL);
								    LPSTR str = HeapAlloc(GetProcessHeap (), 0, count);
								    WideCharToMultiByte(CP_ACP, 0, This->pwzSource, -1, str, count, NULL, NULL);
								    str[count-1] = '\n';
								    TRACE("source:\n");
								    write( 2, str, count );
								    HeapFree(GetProcessHeap(), 0, str);
								}
								break;
						        }
505 506 507
							case DMUS_FOURCC_GUID_CHUNK: {
								TRACE_(dmfile)(": GUID chunk\n");
								This->pDesc->dwValidData |= DMUS_OBJ_OBJECT;
508
								IStream_Read (pStm, &This->pDesc->guidObject, Chunk.dwSize, NULL);
509 510 511 512 513
								break;
							}
							case DMUS_FOURCC_VERSION_CHUNK: {
								TRACE_(dmfile)(": version chunk\n");
								This->pDesc->dwValidData |= DMUS_OBJ_VERSION;
514
								IStream_Read (pStm, &This->pDesc->vVersion, Chunk.dwSize, NULL);
515 516 517 518 519
								break;
							}
							case DMUS_FOURCC_CATEGORY_CHUNK: {
								TRACE_(dmfile)(": category chunk\n");
								This->pDesc->dwValidData |= DMUS_OBJ_CATEGORY;
520
								IStream_Read (pStm, This->pDesc->wszCategory, Chunk.dwSize, NULL);
521 522
								break;
							}
523 524 525
						        case FOURCC_RIFF: {
								IDirectMusicObject* pObject = NULL;
								DMUS_OBJECTDESC desc;
526

527
								ZeroMemory (&desc, sizeof(DMUS_OBJECTDESC));
528
								desc.dwSize = sizeof(DMUS_OBJECTDESC);
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569
								desc.dwValidData = DMUS_OBJ_STREAM | DMUS_OBJ_CLASS;
								desc.guidClass = CLSID_DirectMusicContainer;
								desc.pStream = NULL;
								IStream_Clone (pStm, &desc.pStream);

								liMove.QuadPart = 0;
								liMove.QuadPart -= (sizeof(FOURCC) + sizeof(DWORD));
								IStream_Seek (desc.pStream, liMove, STREAM_SEEK_CUR, NULL);

								IStream_QueryInterface (pStm, &IID_IDirectMusicGetLoader, (LPVOID*)&pGetLoader);
								IDirectMusicGetLoader_GetLoader (pGetLoader, &pLoader);
								IDirectMusicGetLoader_Release (pGetLoader);

								if (SUCCEEDED(IDirectMusicLoader_GetObject (pLoader, &desc, &IID_IDirectMusicObject, (LPVOID*) &pObject))) {
								  IDirectMusicObject_Release (pObject);
								} else {
								  ERR_(dmfile)("Error on GetObject while trying to load Scrip SubContainer\n");
								}

								IDirectMusicLoader_Release (pLoader); pLoader = NULL; /* release loader */
								IStream_Release(desc.pStream); desc.pStream = NULL; /* release cloned stream */

								liMove.QuadPart = Chunk.dwSize;
								IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
								/*
							        IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);				
								TRACE_(dmfile)(": RIFF chunk of type %s", debugstr_fourcc(Chunk.fccID));
								ListSize[0] = Chunk.dwSize - sizeof(FOURCC);
								ListCount[0] = 0;

								switch (Chunk.fccID) {
								        default: {
										TRACE_(dmfile)(": unknown (skipping)\n");
										liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
										IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
										break;						
									}
								}
								*/
								break;
							}
570
							case FOURCC_LIST: {
571 572 573
								IStream_Read (pStm, &Chunk.fccID, sizeof(FOURCC), NULL);				
								TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(Chunk.fccID));
								ListSize[0] = Chunk.dwSize - sizeof(FOURCC);
574
								ListCount[0] = 0;
575
								switch (Chunk.fccID) {
576 577 578
									case DMUS_FOURCC_UNFO_LIST: {
										TRACE_(dmfile)(": UNFO list\n");
										do {
579 580
											IStream_Read (pStm, &Chunk, sizeof(FOURCC)+sizeof(DWORD), NULL);
											ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + Chunk.dwSize;
581
											TRACE_(dmfile)(": %s chunk (size = %d)", debugstr_fourcc (Chunk.fccID), Chunk.dwSize);
582
											switch (Chunk.fccID) {
583 584 585 586 587 588
												/* don't ask me why, but M$ puts INFO elements in UNFO list sometimes
                                              (though strings seem to be valid unicode) */
												case mmioFOURCC('I','N','A','M'):
												case DMUS_FOURCC_UNAM_CHUNK: {
													TRACE_(dmfile)(": name chunk\n");
													This->pDesc->dwValidData |= DMUS_OBJ_NAME;
589
													IStream_Read (pStm, This->pDesc->wszName, Chunk.dwSize, NULL);
590 591 592 593 594
													break;
												}
												case mmioFOURCC('I','A','R','T'):
												case DMUS_FOURCC_UART_CHUNK: {
													TRACE_(dmfile)(": artist chunk (ignored)\n");
595
													liMove.QuadPart = Chunk.dwSize;
596 597 598 599 600 601
													IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
													break;
												}
												case mmioFOURCC('I','C','O','P'):
												case DMUS_FOURCC_UCOP_CHUNK: {
													TRACE_(dmfile)(": copyright chunk (ignored)\n");
602
													liMove.QuadPart = Chunk.dwSize;
603 604 605 606 607 608
													IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
													break;
												}
												case mmioFOURCC('I','S','B','J'):
												case DMUS_FOURCC_USBJ_CHUNK: {
													TRACE_(dmfile)(": subject chunk (ignored)\n");
609
													liMove.QuadPart = Chunk.dwSize;
610 611 612 613 614 615
													IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
													break;
												}
												case mmioFOURCC('I','C','M','T'):
												case DMUS_FOURCC_UCMT_CHUNK: {
													TRACE_(dmfile)(": comment chunk (ignored)\n");
616
													liMove.QuadPart = Chunk.dwSize;
617 618 619 620
													IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
													break;
												}
												default: {
621
													TRACE_(dmfile)(": unknown sub-chunk (irrelevant & skipping)\n");
622
													liMove.QuadPart = Chunk.dwSize;
623 624 625 626
													IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
													break;						
												}
											}
627
											TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]);
628 629 630 631 632
										} while (ListCount[0] < ListSize[0]);
										break;
									}
									default: {
										TRACE_(dmfile)(": unknown (skipping)\n");
633
										liMove.QuadPart = Chunk.dwSize - sizeof(FOURCC);
634 635 636 637 638 639 640
										IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
										break;						
									}
								}
								break;
							}	
							default: {
641
								TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
642
								liMove.QuadPart = Chunk.dwSize;
643 644 645 646
								IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL);
								break;						
							}
						}
647
						TRACE_(dmfile)(": StreamCount[0] = %d < StreamSize[0] = %d\n", StreamCount, StreamSize);
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662
					} while (StreamCount < StreamSize);
					break;
				}
				default: {
					TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
					liMove.QuadPart = StreamSize;
					IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
					return E_FAIL;
				}
			}
			TRACE_(dmfile)(": reading finished\n");
			break;
		}
		default: {
			TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
663
			liMove.QuadPart = Chunk.dwSize;
664 665 666 667 668
			IStream_Seek (pStm, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
			return E_FAIL;
		}
	}

669 670 671
	return S_OK;
}

672
static HRESULT WINAPI IDirectMusicScriptImpl_IPersistStream_Save (LPPERSISTSTREAM iface, IStream* pStm, BOOL fClearDirty) {
673
  return E_NOTIMPL;
674 675
}

676
static HRESULT WINAPI IDirectMusicScriptImpl_IPersistStream_GetSizeMax (LPPERSISTSTREAM iface, ULARGE_INTEGER* pcbSize) {
677
  return E_NOTIMPL;
678 679
}

680
static const IPersistStreamVtbl DirectMusicScript_PersistStream_Vtbl = {
681 682 683 684 685 686 687 688
  IDirectMusicScriptImpl_IPersistStream_QueryInterface,
  IDirectMusicScriptImpl_IPersistStream_AddRef,
  IDirectMusicScriptImpl_IPersistStream_Release,
  IDirectMusicScriptImpl_IPersistStream_GetClassID,
  IDirectMusicScriptImpl_IPersistStream_IsDirty,
  IDirectMusicScriptImpl_IPersistStream_Load,
  IDirectMusicScriptImpl_IPersistStream_Save,
  IDirectMusicScriptImpl_IPersistStream_GetSizeMax
689
};
690 691 692

/* for ClassFactory */
HRESULT WINAPI DMUSIC_CreateDirectMusicScriptImpl (LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter) {
693 694 695 696
  IDirectMusicScriptImpl* obj;
  
  obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicScriptImpl));
  if (NULL == obj) {
697
    *ppobj = NULL;
698 699 700 701 702 703 704 705 706
    return E_OUTOFMEMORY;
  }
  obj->UnknownVtbl = &DirectMusicScript_Unknown_Vtbl;
  obj->ScriptVtbl = &DirectMusicScript_Script_Vtbl;
  obj->ObjectVtbl = &DirectMusicScript_Object_Vtbl;
  obj->PersistStreamVtbl = &DirectMusicScript_PersistStream_Vtbl;
  obj->pDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DMUS_OBJECTDESC));
  DM_STRUCT_INIT(obj->pDesc);
  obj->pDesc->dwValidData |= DMUS_OBJ_CLASS;
707
  obj->pDesc->guidClass = CLSID_DirectMusicScript;
708
  obj->ref = 0; /* will be inited by QueryInterface */
709

710
  return IDirectMusicScriptImpl_IUnknown_QueryInterface ((LPUNKNOWN)&obj->UnknownVtbl, lpcGUID, ppobj);
711
}