e0596ab93301715b43aaf09a28dde52c77a09b47
[reactos.git] / reactos / dll / directx / wine / dmusic / collection.c
1 /*
2 * IDirectMusicCollection Implementation
3 *
4 * Copyright (C) 2003-2004 Rok Mandeljc
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include "dmusic_private.h"
22
23 WINE_DECLARE_DEBUG_CHANNEL(dmfile);
24
25 static inline IDirectMusicCollectionImpl *impl_from_IDirectMusicCollection(IDirectMusicCollection *iface)
26 {
27 return CONTAINING_RECORD(iface, IDirectMusicCollectionImpl, IDirectMusicCollection_iface);
28 }
29
30 static inline IDirectMusicCollectionImpl *impl_from_IDirectMusicObject(IDirectMusicObject *iface)
31 {
32 return CONTAINING_RECORD(iface, IDirectMusicCollectionImpl, IDirectMusicObject_iface);
33 }
34
35 static inline IDirectMusicCollectionImpl *impl_from_IPersistStream(IPersistStream *iface)
36 {
37 return CONTAINING_RECORD(iface, IDirectMusicCollectionImpl, IPersistStream_iface);
38 }
39
40 /*****************************************************************************
41 * IDirectMusicCollectionImpl implementation
42 */
43 /* IDirectMusicCollectionImpl IUnknown part: */
44 static HRESULT WINAPI IDirectMusicCollectionImpl_IDirectMusicCollection_QueryInterface(LPDIRECTMUSICCOLLECTION iface, REFIID riid, LPVOID *ret_iface)
45 {
46 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface);
47
48 TRACE("(%p/%p)->(%s, %p)\n", iface, This, debugstr_dmguid(riid), ret_iface);
49
50 if (IsEqualIID(riid, &IID_IUnknown) ||
51 IsEqualIID(riid, &IID_IDirectMusicCollection))
52 {
53 *ret_iface = iface;
54 IDirectMusicCollection_AddRef(iface);
55 return S_OK;
56 }
57 else if (IsEqualIID(riid, &IID_IDirectMusicObject))
58 {
59 *ret_iface = &This->IDirectMusicObject_iface;
60 IDirectMusicCollection_AddRef(iface);
61 return S_OK;
62 }
63 else if (IsEqualIID(riid, &IID_IPersistStream))
64 {
65 *ret_iface = &This->IPersistStream_iface;
66 IDirectMusicCollection_AddRef(iface);
67 return S_OK;
68 }
69
70 *ret_iface = NULL;
71
72 WARN("(%p/%p)->(%s, %p): not found\n", iface, This, debugstr_dmguid(riid), ret_iface);
73
74 return E_NOINTERFACE;
75 }
76
77 static ULONG WINAPI IDirectMusicCollectionImpl_IDirectMusicCollection_AddRef(LPDIRECTMUSICCOLLECTION iface)
78 {
79 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface);
80 ULONG ref = InterlockedIncrement(&This->ref);
81
82 TRACE("(%p/%p)->(): new ref = %u\n", iface, This, ref);
83
84 DMUSIC_LockModule();
85
86 return ref;
87 }
88
89 static ULONG WINAPI IDirectMusicCollectionImpl_IDirectMusicCollection_Release(LPDIRECTMUSICCOLLECTION iface)
90 {
91 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface);
92 ULONG ref = InterlockedDecrement(&This->ref);
93
94 TRACE("(%p/%p)->(): new ref = %u\n", iface, This, ref);
95
96 if (!ref)
97 HeapFree(GetProcessHeap(), 0, This);
98
99 DMUSIC_UnlockModule();
100
101 return ref;
102 }
103
104 /* IDirectMusicCollection Interface follows: */
105 static HRESULT WINAPI IDirectMusicCollectionImpl_IDirectMusicCollection_GetInstrument(LPDIRECTMUSICCOLLECTION iface, DWORD patch, IDirectMusicInstrument** instrument)
106 {
107 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface);
108 DMUS_PRIVATE_INSTRUMENTENTRY *inst_entry;
109 struct list *list_entry;
110 DWORD inst_patch;
111
112 TRACE("(%p/%p)->(%u, %p)\n", iface, This, patch, instrument);
113
114 LIST_FOR_EACH(list_entry, &This->Instruments) {
115 inst_entry = LIST_ENTRY(list_entry, DMUS_PRIVATE_INSTRUMENTENTRY, entry);
116 IDirectMusicInstrument_GetPatch(inst_entry->pInstrument, &inst_patch);
117 if (patch == inst_patch) {
118 *instrument = inst_entry->pInstrument;
119 IDirectMusicInstrument_AddRef(inst_entry->pInstrument);
120 IDirectMusicInstrumentImpl_CustomLoad(inst_entry->pInstrument, This->pStm);
121 TRACE(": returning instrument %p\n", *instrument);
122 return S_OK;
123 }
124 }
125
126 TRACE(": instrument not found\n");
127
128 return DMUS_E_INVALIDPATCH;
129 }
130
131 static HRESULT WINAPI IDirectMusicCollectionImpl_IDirectMusicCollection_EnumInstrument(LPDIRECTMUSICCOLLECTION iface, DWORD index, DWORD* patch, LPWSTR name, DWORD name_length)
132 {
133 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface);
134 DWORD i = 0;
135 DMUS_PRIVATE_INSTRUMENTENTRY *inst_entry;
136 struct list *list_entry;
137 DWORD length;
138
139 TRACE("(%p/%p)->(%d, %p, %p, %d)\n", iface, This, index, patch, name, name_length);
140
141 LIST_FOR_EACH(list_entry, &This->Instruments) {
142 inst_entry = LIST_ENTRY(list_entry, DMUS_PRIVATE_INSTRUMENTENTRY, entry);
143 if (i == index) {
144 IDirectMusicInstrumentImpl *instrument = impl_from_IDirectMusicInstrument(inst_entry->pInstrument);
145 IDirectMusicInstrument_GetPatch(inst_entry->pInstrument, patch);
146 if (name) {
147 length = min(strlenW(instrument->wszName), name_length - 1);
148 memcpy(name, instrument->wszName, length * sizeof(WCHAR));
149 name[length] = '\0';
150 }
151 return S_OK;
152 }
153 i++;
154 }
155
156 return S_FALSE;
157 }
158
159 static const IDirectMusicCollectionVtbl DirectMusicCollection_Collection_Vtbl = {
160 IDirectMusicCollectionImpl_IDirectMusicCollection_QueryInterface,
161 IDirectMusicCollectionImpl_IDirectMusicCollection_AddRef,
162 IDirectMusicCollectionImpl_IDirectMusicCollection_Release,
163 IDirectMusicCollectionImpl_IDirectMusicCollection_GetInstrument,
164 IDirectMusicCollectionImpl_IDirectMusicCollection_EnumInstrument
165 };
166
167 /* IDirectMusicCollectionImpl IDirectMusicObject part: */
168 static HRESULT WINAPI IDirectMusicCollectionImpl_IDirectMusicObject_QueryInterface(LPDIRECTMUSICOBJECT iface, REFIID riid, LPVOID *ret_iface)
169 {
170 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicObject(iface);
171 return IDirectMusicCollection_QueryInterface(&This->IDirectMusicCollection_iface, riid, ret_iface);
172 }
173
174 static ULONG WINAPI IDirectMusicCollectionImpl_IDirectMusicObject_AddRef(LPDIRECTMUSICOBJECT iface)
175 {
176 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicObject(iface);
177 return IDirectMusicCollection_AddRef(&This->IDirectMusicCollection_iface);
178 }
179
180 static ULONG WINAPI IDirectMusicCollectionImpl_IDirectMusicObject_Release(LPDIRECTMUSICOBJECT iface)
181 {
182 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicObject(iface);
183 return IDirectMusicCollection_Release(&This->IDirectMusicCollection_iface);
184 }
185
186 static HRESULT WINAPI IDirectMusicCollectionImpl_IDirectMusicObject_GetDescriptor(LPDIRECTMUSICOBJECT iface, LPDMUS_OBJECTDESC pDesc)
187 {
188 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicObject(iface);
189
190 TRACE("(%p/%p)->(%p)\n", iface, This, pDesc);
191
192 /* I think we shouldn't return pointer here since then values can be changed; it'd be a mess */
193 memcpy (pDesc, This->pDesc, This->pDesc->dwSize);
194
195 return S_OK;
196 }
197
198 static HRESULT WINAPI IDirectMusicCollectionImpl_IDirectMusicObject_SetDescriptor(LPDIRECTMUSICOBJECT iface, LPDMUS_OBJECTDESC pDesc)
199 {
200 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicObject(iface);
201
202 TRACE("(%p, %p)\n", iface, pDesc);
203
204 if (!pDesc)
205 return E_POINTER;
206
207 if (TRACE_ON(dmusic))
208 {
209 TRACE("Setting descriptor:\n");
210 dump_DMUS_OBJECTDESC(pDesc);
211 }
212
213 /* According to MSDN, we should copy only given values, not whole struct */
214 if (pDesc->dwValidData & DMUS_OBJ_OBJECT)
215 This->pDesc->guidObject = pDesc->guidObject;
216 if (pDesc->dwValidData & DMUS_OBJ_CLASS)
217 This->pDesc->guidClass = pDesc->guidClass;
218 if (pDesc->dwValidData & DMUS_OBJ_NAME)
219 lstrcpynW(This->pDesc->wszName, pDesc->wszName, DMUS_MAX_NAME);
220 if (pDesc->dwValidData & DMUS_OBJ_CATEGORY)
221 lstrcpynW(This->pDesc->wszCategory, pDesc->wszCategory, DMUS_MAX_CATEGORY);
222 if (pDesc->dwValidData & DMUS_OBJ_FILENAME)
223 lstrcpynW(This->pDesc->wszFileName, pDesc->wszFileName, DMUS_MAX_FILENAME);
224 if (pDesc->dwValidData & DMUS_OBJ_VERSION)
225 This->pDesc->vVersion = pDesc->vVersion;
226 if (pDesc->dwValidData & DMUS_OBJ_DATE)
227 This->pDesc->ftDate = pDesc->ftDate;
228 if (pDesc->dwValidData & DMUS_OBJ_MEMORY) {
229 This->pDesc->llMemLength = pDesc->llMemLength;
230 memcpy (This->pDesc->pbMemData, pDesc->pbMemData, pDesc->llMemLength);
231 }
232 if (pDesc->dwValidData & DMUS_OBJ_STREAM) {
233 /* according to MSDN, we copy the stream */
234 IStream_Clone (pDesc->pStream, &This->pDesc->pStream);
235 }
236
237 /* add new flags */
238 This->pDesc->dwValidData |= pDesc->dwValidData;
239
240 return S_OK;
241 }
242
243 static HRESULT read_from_stream(IStream *stream, void *data, ULONG size)
244 {
245 ULONG read;
246 HRESULT hr;
247
248 hr = IStream_Read(stream, data, size, &read);
249 if (FAILED(hr)) {
250 TRACE("IStream_Read failed: %08x\n", hr);
251 return hr;
252 }
253 if (read < size) {
254 TRACE("Didn't read full chunk: %u < %u\n", read, size);
255 return E_FAIL;
256 }
257
258 return S_OK;
259 }
260
261 static HRESULT WINAPI IDirectMusicCollectionImpl_IDirectMusicObject_ParseDescriptor(LPDIRECTMUSICOBJECT iface, LPSTREAM stream, LPDMUS_OBJECTDESC desc)
262 {
263 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicObject(iface);
264 DMUS_PRIVATE_CHUNK chunk;
265 DWORD StreamSize, StreamCount, ListSize[1], ListCount[1];
266 LARGE_INTEGER liMove; /* used when skipping chunks */
267 HRESULT hr;
268
269 TRACE("(%p)->(%p, %p)\n", This, stream, desc);
270
271 /* FIXME: should this be determined from stream? */
272 desc->dwValidData |= DMUS_OBJ_CLASS;
273 desc->guidClass = CLSID_DirectMusicCollection;
274
275 hr = read_from_stream(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD));
276 if (FAILED(hr))
277 return hr;
278 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
279
280 if (chunk.fccID != FOURCC_RIFF) {
281 TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
282 liMove.QuadPart = chunk.dwSize;
283 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
284 return DMUS_E_INVALIDFILE;
285 }
286
287 hr = read_from_stream(stream, &chunk.fccID, sizeof(FOURCC));
288 if (FAILED(hr))
289 return hr;
290 TRACE_(dmfile)(": RIFF chunk of type %s", debugstr_fourcc(chunk.fccID));
291 StreamSize = chunk.dwSize - sizeof(FOURCC);
292
293 if (chunk.fccID != mmioFOURCC('D','L','S',' ')) {
294 TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
295 liMove.QuadPart = StreamSize;
296 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
297 return E_FAIL;
298 }
299
300 StreamCount = 0;
301 TRACE_(dmfile)(": collection form\n");
302
303 do {
304 hr = read_from_stream(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD));
305 if (FAILED(hr))
306 return hr;
307 StreamCount += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize;
308 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
309 switch (chunk.fccID) {
310 case FOURCC_DLID:
311 TRACE_(dmfile)(": GUID chunk\n");
312 desc->dwValidData |= DMUS_OBJ_OBJECT;
313 hr = read_from_stream(stream, &desc->guidObject, chunk.dwSize);
314 if (FAILED(hr))
315 return hr;
316 break;
317
318 case DMUS_FOURCC_VERSION_CHUNK:
319 TRACE_(dmfile)(": version chunk\n");
320 desc->dwValidData |= DMUS_OBJ_VERSION;
321 hr = read_from_stream(stream, &desc->vVersion, chunk.dwSize);
322 if (FAILED(hr))
323 return hr;
324 break;
325
326 case DMUS_FOURCC_CATEGORY_CHUNK:
327 TRACE_(dmfile)(": category chunk\n");
328 desc->dwValidData |= DMUS_OBJ_CATEGORY;
329 hr = read_from_stream(stream, desc->wszCategory, chunk.dwSize);
330 if (FAILED(hr))
331 return hr;
332 break;
333
334 case FOURCC_LIST:
335 hr = read_from_stream(stream, &chunk.fccID, sizeof(FOURCC));
336 if (FAILED(hr))
337 return hr;
338 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(chunk.fccID));
339 ListSize[0] = chunk.dwSize - sizeof(FOURCC);
340 ListCount[0] = 0;
341 switch (chunk.fccID) {
342 /* pure INFO list, such can be found in dls collections */
343 case mmioFOURCC('I','N','F','O'):
344 TRACE_(dmfile)(": INFO list\n");
345 do {
346 hr = read_from_stream(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD));
347 if (FAILED(hr))
348 return hr;
349 ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize;
350 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
351 switch (chunk.fccID) {
352 case mmioFOURCC('I','N','A','M'): {
353 CHAR szName[DMUS_MAX_NAME];
354 TRACE_(dmfile)(": name chunk\n");
355 desc->dwValidData |= DMUS_OBJ_NAME;
356 hr = read_from_stream(stream, szName, chunk.dwSize);
357 if (FAILED(hr))
358 return hr;
359 MultiByteToWideChar (CP_ACP, 0, szName, -1, desc->wszName, DMUS_MAX_NAME);
360 if (even_or_odd(chunk.dwSize)) {
361 ListCount[0]++;
362 liMove.QuadPart = 1;
363 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
364 }
365 break;
366 }
367
368 case mmioFOURCC('I','A','R','T'):
369 TRACE_(dmfile)(": artist chunk (ignored)\n");
370 if (even_or_odd(chunk.dwSize)) {
371 ListCount[0]++;
372 chunk.dwSize++;
373 }
374 liMove.QuadPart = chunk.dwSize;
375 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
376 break;
377
378 case mmioFOURCC('I','C','O','P'):
379 TRACE_(dmfile)(": copyright chunk (ignored)\n");
380 if (even_or_odd(chunk.dwSize)) {
381 ListCount[0]++;
382 chunk.dwSize++;
383 }
384 liMove.QuadPart = chunk.dwSize;
385 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
386 break;
387
388 case mmioFOURCC('I','S','B','J'):
389 TRACE_(dmfile)(": subject chunk (ignored)\n");
390 if (even_or_odd(chunk.dwSize)) {
391 ListCount[0]++;
392 chunk.dwSize++;
393 }
394 liMove.QuadPart = chunk.dwSize;
395 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
396 break;
397
398 case mmioFOURCC('I','C','M','T'):
399 TRACE_(dmfile)(": comment chunk (ignored)\n");
400 if (even_or_odd(chunk.dwSize)) {
401 ListCount[0]++;
402 chunk.dwSize++;
403 liMove.QuadPart = chunk.dwSize;
404 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
405 break;
406 }
407
408 default:
409 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
410 if (even_or_odd(chunk.dwSize)) {
411 ListCount[0] ++;
412 chunk.dwSize++;
413 }
414 liMove.QuadPart = chunk.dwSize;
415 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
416 break;
417 }
418 TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]);
419 } while (ListCount[0] < ListSize[0]);
420 break;
421
422 default:
423 TRACE_(dmfile)(": unknown (skipping)\n");
424 liMove.QuadPart = chunk.dwSize - sizeof(FOURCC);
425 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
426 break;
427 }
428 break;
429
430 default:
431 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
432 liMove.QuadPart = chunk.dwSize;
433 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
434 break;
435 }
436 TRACE_(dmfile)(": StreamCount[0] = %d < StreamSize[0] = %d\n", StreamCount, StreamSize);
437 } while (StreamCount < StreamSize);
438
439 TRACE_(dmfile)(": reading finished\n");
440
441 if (TRACE_ON(dmusic)) {
442 TRACE("Returning descriptor:\n");
443 dump_DMUS_OBJECTDESC(desc);
444 }
445
446 return S_OK;
447 }
448
449 static const IDirectMusicObjectVtbl DirectMusicCollection_Object_Vtbl = {
450 IDirectMusicCollectionImpl_IDirectMusicObject_QueryInterface,
451 IDirectMusicCollectionImpl_IDirectMusicObject_AddRef,
452 IDirectMusicCollectionImpl_IDirectMusicObject_Release,
453 IDirectMusicCollectionImpl_IDirectMusicObject_GetDescriptor,
454 IDirectMusicCollectionImpl_IDirectMusicObject_SetDescriptor,
455 IDirectMusicCollectionImpl_IDirectMusicObject_ParseDescriptor
456 };
457
458 /* IDirectMusicCollectionImpl IPersistStream part: */
459 static HRESULT WINAPI IDirectMusicCollectionImpl_IPersistStream_QueryInterface(LPPERSISTSTREAM iface, REFIID riid, LPVOID *ret_iface)
460 {
461 IDirectMusicCollectionImpl *This = impl_from_IPersistStream(iface);
462 return IDirectMusicCollection_QueryInterface(&This->IDirectMusicCollection_iface, riid, ret_iface);
463 }
464
465 static ULONG WINAPI IDirectMusicCollectionImpl_IPersistStream_AddRef (LPPERSISTSTREAM iface)
466 {
467 IDirectMusicCollectionImpl *This = impl_from_IPersistStream(iface);
468 return IDirectMusicCollection_AddRef(&This->IDirectMusicCollection_iface);
469 }
470
471 static ULONG WINAPI IDirectMusicCollectionImpl_IPersistStream_Release (LPPERSISTSTREAM iface)
472 {
473 IDirectMusicCollectionImpl *This = impl_from_IPersistStream(iface);
474 return IDirectMusicCollection_Release(&This->IDirectMusicCollection_iface);
475 }
476
477 static HRESULT WINAPI IDirectMusicCollectionImpl_IPersistStream_GetClassID(LPPERSISTSTREAM iface, CLSID* pClassID)
478 {
479 return E_NOTIMPL;
480 }
481
482 static HRESULT WINAPI IDirectMusicCollectionImpl_IPersistStream_IsDirty(LPPERSISTSTREAM iface)
483 {
484 return E_NOTIMPL;
485 }
486
487 static HRESULT WINAPI IDirectMusicCollectionImpl_IPersistStream_Load(LPPERSISTSTREAM iface, IStream* stream)
488 {
489 IDirectMusicCollectionImpl *This = impl_from_IPersistStream(iface);
490 DMUS_PRIVATE_CHUNK chunk;
491 DWORD StreamSize, StreamCount, ListSize[2], ListCount[2];
492 LARGE_INTEGER liMove; /* used when skipping chunks */
493 ULARGE_INTEGER dlibCollectionPosition, dlibInstrumentPosition, dlibWavePoolPosition;
494
495 IStream_AddRef(stream); /* add count for later references */
496 liMove.QuadPart = 0;
497 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, &dlibCollectionPosition); /* store offset, in case it'll be needed later */
498 This->liCollectionPosition.QuadPart = dlibCollectionPosition.QuadPart;
499 This->pStm = stream;
500
501 IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL);
502 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
503
504 if (chunk.fccID != FOURCC_RIFF) {
505 TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
506 liMove.QuadPart = chunk.dwSize;
507 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
508 return E_FAIL;
509 }
510
511 IStream_Read(stream, &chunk.fccID, sizeof(FOURCC), NULL);
512 TRACE_(dmfile)(": RIFF chunk of type %s", debugstr_fourcc(chunk.fccID));
513 StreamSize = chunk.dwSize - sizeof(FOURCC);
514 StreamCount = 0;
515
516 if (chunk.fccID != FOURCC_DLS) {
517 TRACE_(dmfile)(": unexpected chunk; loading failed)\n");
518 liMove.QuadPart = StreamSize;
519 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */
520 return E_FAIL;
521 }
522
523 TRACE_(dmfile)(": collection form\n");
524 do {
525 IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL);
526 StreamCount += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize;
527 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
528 switch (chunk.fccID) {
529 case FOURCC_COLH: {
530 TRACE_(dmfile)(": collection header chunk\n");
531 This->pHeader = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, chunk.dwSize);
532 IStream_Read(stream, This->pHeader, chunk.dwSize, NULL);
533 break;
534 }
535 case FOURCC_DLID: {
536 TRACE_(dmfile)(": DLID (GUID) chunk\n");
537 This->pDesc->dwValidData |= DMUS_OBJ_OBJECT;
538 IStream_Read(stream, &This->pDesc->guidObject, chunk.dwSize, NULL);
539 break;
540 }
541 case FOURCC_VERS: {
542 TRACE_(dmfile)(": version chunk\n");
543 This->pDesc->dwValidData |= DMUS_OBJ_VERSION;
544 IStream_Read(stream, &This->pDesc->vVersion, chunk.dwSize, NULL);
545 break;
546 }
547 case FOURCC_PTBL: {
548 TRACE_(dmfile)(": pool table chunk\n");
549 This->pPoolTable = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(POOLTABLE));
550 IStream_Read(stream, This->pPoolTable, sizeof(POOLTABLE), NULL);
551 chunk.dwSize -= sizeof(POOLTABLE);
552 This->pPoolCues = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pPoolTable->cCues * sizeof(POOLCUE));
553 IStream_Read(stream, This->pPoolCues, chunk.dwSize, NULL);
554 break;
555 }
556 case FOURCC_LIST: {
557 IStream_Read(stream, &chunk.fccID, sizeof(FOURCC), NULL);
558 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(chunk.fccID));
559 ListSize[0] = chunk.dwSize - sizeof(FOURCC);
560 ListCount[0] = 0;
561 switch (chunk.fccID) {
562 case mmioFOURCC('I','N','F','O'): {
563 TRACE_(dmfile)(": INFO list\n");
564 do {
565 IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL);
566 ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize;
567 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
568 switch (chunk.fccID) {
569 case mmioFOURCC('I','N','A','M'): {
570 CHAR szName[DMUS_MAX_NAME];
571 TRACE_(dmfile)(": name chunk\n");
572 This->pDesc->dwValidData |= DMUS_OBJ_NAME;
573 IStream_Read(stream, szName, chunk.dwSize, NULL);
574 MultiByteToWideChar(CP_ACP, 0, szName, -1, This->pDesc->wszName, DMUS_MAX_NAME);
575 if (even_or_odd(chunk.dwSize)) {
576 ListCount[0]++;
577 liMove.QuadPart = 1;
578 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
579 }
580 break;
581 }
582 case mmioFOURCC('I','A','R','T'): {
583 TRACE_(dmfile)(": artist chunk (ignored)\n");
584 if (even_or_odd(chunk.dwSize)) {
585 ListCount[0]++;
586 chunk.dwSize++;
587 }
588 liMove.QuadPart = chunk.dwSize;
589 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
590 break;
591 }
592 case mmioFOURCC('I','C','O','P'): {
593 TRACE_(dmfile)(": copyright chunk\n");
594 This->szCopyright = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, chunk.dwSize);
595 IStream_Read(stream, This->szCopyright, chunk.dwSize, NULL);
596 if (even_or_odd(chunk.dwSize)) {
597 ListCount[0]++;
598 liMove.QuadPart = 1;
599 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
600 }
601 break;
602 }
603 case mmioFOURCC('I','S','B','J'): {
604 TRACE_(dmfile)(": subject chunk (ignored)\n");
605 if (even_or_odd(chunk.dwSize)) {
606 ListCount[0]++;
607 chunk.dwSize++;
608 }
609 liMove.QuadPart = chunk.dwSize;
610 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
611 break;
612 }
613 case mmioFOURCC('I','C','M','T'): {
614 TRACE_(dmfile)(": comment chunk (ignored)\n");
615 if (even_or_odd(chunk.dwSize)) {
616 ListCount[0]++;
617 chunk.dwSize++;
618 }
619 liMove.QuadPart = chunk.dwSize;
620 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
621 break;
622 }
623 default: {
624 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
625 if (even_or_odd(chunk.dwSize)) {
626 ListCount[0]++;
627 chunk.dwSize++;
628 }
629 liMove.QuadPart = chunk.dwSize;
630 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
631 break;
632 }
633 }
634 TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]);
635 } while (ListCount[0] < ListSize[0]);
636 break;
637 }
638 case FOURCC_WVPL: {
639 TRACE_(dmfile)(": wave pool list (mark & skip)\n");
640 liMove.QuadPart = 0;
641 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, &dlibWavePoolPosition); /* store position */
642 This->liWavePoolTablePosition.QuadPart = dlibWavePoolPosition.QuadPart;
643 liMove.QuadPart = chunk.dwSize - sizeof(FOURCC);
644 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
645 break;
646 }
647 case FOURCC_LINS: {
648 TRACE_(dmfile)(": instruments list\n");
649 do {
650 IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL);
651 ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize;
652 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
653 switch (chunk.fccID) {
654 case FOURCC_LIST: {
655 IStream_Read(stream, &chunk.fccID, sizeof(FOURCC), NULL);
656 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(chunk.fccID));
657 ListSize[1] = chunk.dwSize - sizeof(FOURCC);
658 ListCount[1] = 0;
659 switch (chunk.fccID) {
660 case FOURCC_INS: {
661 LPDMUS_PRIVATE_INSTRUMENTENTRY new_instrument = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DMUS_PRIVATE_INSTRUMENTENTRY));
662 TRACE_(dmfile)(": instrument list\n");
663 /* Only way to create this one... even M$ does it discretely */
664 DMUSIC_CreateDirectMusicInstrumentImpl(&IID_IDirectMusicInstrument, (void**)&new_instrument->pInstrument, NULL);
665 {
666 IDirectMusicInstrumentImpl *instrument = impl_from_IDirectMusicInstrument(new_instrument->pInstrument);
667 /* Store offset and length, they will be needed when loading the instrument */
668 liMove.QuadPart = 0;
669 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, &dlibInstrumentPosition);
670 instrument->liInstrumentPosition.QuadPart = dlibInstrumentPosition.QuadPart;
671 instrument->length = ListSize[1];
672 do {
673 IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL);
674 ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize;
675 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize);
676 switch (chunk.fccID) {
677 case FOURCC_INSH: {
678 TRACE_(dmfile)(": instrument header chunk\n");
679 IStream_Read(stream, &instrument->header, chunk.dwSize, NULL);
680 break;
681 }
682 case FOURCC_DLID: {
683 TRACE_(dmfile)(": DLID (GUID) chunk\n");
684 IStream_Read(stream, &instrument->id, chunk.dwSize, NULL);
685 break;
686 }
687 case FOURCC_LIST: {
688 IStream_Read(stream, &chunk.fccID, sizeof(FOURCC), NULL);
689 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(chunk.fccID));
690 switch (chunk.fccID) {
691 default: {
692 TRACE_(dmfile)(": unknown (skipping)\n");
693 liMove.QuadPart = chunk.dwSize - sizeof(FOURCC);
694 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
695 break;
696 }
697 }
698 break;
699 }
700 default: {
701 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
702 liMove.QuadPart = chunk.dwSize;
703 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
704 break;
705 }
706 }
707 TRACE_(dmfile)(": ListCount[1] = %d < ListSize[1] = %d\n", ListCount[1], ListSize[1]);
708 } while (ListCount[1] < ListSize[1]);
709 /* DEBUG: dumps whole instrument object tree: */
710 if (TRACE_ON(dmusic)) {
711 TRACE("*** IDirectMusicInstrument (%p) ***\n", instrument);
712 if (!IsEqualGUID(&instrument->id, &GUID_NULL))
713 TRACE(" - GUID = %s\n", debugstr_dmguid(&instrument->id));
714 TRACE(" - Instrument header:\n");
715 TRACE(" - cRegions: %d\n", instrument->header.cRegions);
716 TRACE(" - Locale:\n");
717 TRACE(" - ulBank: %d\n", instrument->header.Locale.ulBank);
718 TRACE(" - ulInstrument: %d\n", instrument->header.Locale.ulInstrument);
719 TRACE(" => dwPatch: %d\n", MIDILOCALE2Patch(&instrument->header.Locale));
720 }
721 list_add_tail(&This->Instruments, &new_instrument->entry);
722 }
723 break;
724 }
725 }
726 break;
727 }
728 default: {
729 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
730 liMove.QuadPart = chunk.dwSize;
731 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
732 break;
733 }
734 }
735 TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]);
736 } while (ListCount[0] < ListSize[0]);
737 break;
738 }
739 default: {
740 TRACE_(dmfile)(": unknown (skipping)\n");
741 liMove.QuadPart = chunk.dwSize - sizeof(FOURCC);
742 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
743 break;
744 }
745 }
746 break;
747 }
748 default: {
749 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n");
750 liMove.QuadPart = chunk.dwSize;
751 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL);
752 break;
753 }
754 }
755 TRACE_(dmfile)(": StreamCount = %d < StreamSize = %d\n", StreamCount, StreamSize);
756 } while (StreamCount < StreamSize);
757
758 TRACE_(dmfile)(": reading finished\n");
759
760
761 /* DEBUG: dumps whole collection object tree: */
762 if (TRACE_ON(dmusic)) {
763 int r = 0;
764 DMUS_PRIVATE_INSTRUMENTENTRY *tmpEntry;
765 struct list *listEntry;
766
767 TRACE("*** IDirectMusicCollection (%p) ***\n", &This->IDirectMusicCollection_iface);
768 if (This->pDesc->dwValidData & DMUS_OBJ_OBJECT)
769 TRACE(" - GUID = %s\n", debugstr_dmguid(&This->pDesc->guidObject));
770 if (This->pDesc->dwValidData & DMUS_OBJ_VERSION)
771 TRACE(" - Version = %i,%i,%i,%i\n", (This->pDesc->vVersion.dwVersionMS >> 8) & 0x0000FFFF, This->pDesc->vVersion.dwVersionMS & 0x0000FFFF,
772 (This->pDesc->vVersion.dwVersionLS >> 8) & 0x0000FFFF, This->pDesc->vVersion.dwVersionLS & 0x0000FFFF);
773 if (This->pDesc->dwValidData & DMUS_OBJ_NAME)
774 TRACE(" - Name = %s\n", debugstr_w(This->pDesc->wszName));
775
776 TRACE(" - Collection header:\n");
777 TRACE(" - cInstruments: %d\n", This->pHeader->cInstruments);
778 TRACE(" - Instruments:\n");
779
780 LIST_FOR_EACH(listEntry, &This->Instruments) {
781 tmpEntry = LIST_ENTRY( listEntry, DMUS_PRIVATE_INSTRUMENTENTRY, entry );
782 TRACE(" - Instrument[%i]: %p\n", r, tmpEntry->pInstrument);
783 r++;
784 }
785 }
786
787 return S_OK;
788 }
789
790 static HRESULT WINAPI IDirectMusicCollectionImpl_IPersistStream_Save(LPPERSISTSTREAM iface, IStream* pStm, BOOL fClearDirty)
791 {
792 return E_NOTIMPL;
793 }
794
795 static HRESULT WINAPI IDirectMusicCollectionImpl_IPersistStream_GetSizeMax(LPPERSISTSTREAM iface, ULARGE_INTEGER* pcbSize)
796 {
797 return E_NOTIMPL;
798 }
799
800 static const IPersistStreamVtbl DirectMusicCollection_PersistStream_Vtbl = {
801 IDirectMusicCollectionImpl_IPersistStream_QueryInterface,
802 IDirectMusicCollectionImpl_IPersistStream_AddRef,
803 IDirectMusicCollectionImpl_IPersistStream_Release,
804 IDirectMusicCollectionImpl_IPersistStream_GetClassID,
805 IDirectMusicCollectionImpl_IPersistStream_IsDirty,
806 IDirectMusicCollectionImpl_IPersistStream_Load,
807 IDirectMusicCollectionImpl_IPersistStream_Save,
808 IDirectMusicCollectionImpl_IPersistStream_GetSizeMax
809 };
810
811
812 /* for ClassFactory */
813 HRESULT WINAPI DMUSIC_CreateDirectMusicCollectionImpl(LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter)
814 {
815 IDirectMusicCollectionImpl* obj;
816
817 obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicCollectionImpl));
818 if (NULL == obj) {
819 *ppobj = NULL;
820 return E_OUTOFMEMORY;
821 }
822 obj->IDirectMusicCollection_iface.lpVtbl = &DirectMusicCollection_Collection_Vtbl;
823 obj->IDirectMusicObject_iface.lpVtbl = &DirectMusicCollection_Object_Vtbl;
824 obj->IPersistStream_iface.lpVtbl = &DirectMusicCollection_PersistStream_Vtbl;
825 obj->pDesc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DMUS_OBJECTDESC));
826 DM_STRUCT_INIT(obj->pDesc);
827 obj->pDesc->dwValidData |= DMUS_OBJ_CLASS;
828 obj->pDesc->guidClass = CLSID_DirectMusicCollection;
829 obj->ref = 0; /* will be inited by QueryInterface */
830 list_init (&obj->Instruments);
831
832 return IDirectMusicCollection_QueryInterface(&obj->IDirectMusicCollection_iface, lpcGUID, ppobj);
833 }