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 #include "dmobject.h" 23 24 WINE_DEFAULT_DEBUG_CHANNEL(dmusic); 25 WINE_DECLARE_DEBUG_CHANNEL(dmfile); 26 27 /***************************************************************************** 28 * IDirectMusicCollectionImpl implementation 29 */ 30 typedef struct IDirectMusicCollectionImpl { 31 IDirectMusicCollection IDirectMusicCollection_iface; 32 struct dmobject dmobj; 33 LONG ref; 34 /* IDirectMusicCollectionImpl fields */ 35 IStream *pStm; /* stream from which we load collection and later instruments */ 36 LARGE_INTEGER liCollectionPosition; /* offset in a stream where collection was loaded from */ 37 LARGE_INTEGER liWavePoolTablePosition; /* offset in a stream where wave pool table can be found */ 38 CHAR *szCopyright; /* FIXME: should probably be placed somewhere else */ 39 DLSHEADER *pHeader; 40 /* pool table */ 41 POOLTABLE *pPoolTable; 42 POOLCUE *pPoolCues; 43 /* instruments */ 44 struct list Instruments; 45 } IDirectMusicCollectionImpl; 46 47 static inline IDirectMusicCollectionImpl *impl_from_IDirectMusicCollection(IDirectMusicCollection *iface) 48 { 49 return CONTAINING_RECORD(iface, IDirectMusicCollectionImpl, IDirectMusicCollection_iface); 50 } 51 52 static inline struct dmobject *impl_from_IDirectMusicObject(IDirectMusicObject *iface) 53 { 54 return CONTAINING_RECORD(iface, struct dmobject, IDirectMusicObject_iface); 55 } 56 57 static inline IDirectMusicCollectionImpl *impl_from_IPersistStream(IPersistStream *iface) 58 { 59 return CONTAINING_RECORD(iface, IDirectMusicCollectionImpl, dmobj.IPersistStream_iface); 60 } 61 62 /* IDirectMusicCollectionImpl IUnknown part: */ 63 static HRESULT WINAPI IDirectMusicCollectionImpl_QueryInterface(IDirectMusicCollection *iface, 64 REFIID riid, void **ret_iface) 65 { 66 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface); 67 68 TRACE("(%p/%p)->(%s, %p)\n", iface, This, debugstr_dmguid(riid), ret_iface); 69 70 *ret_iface = NULL; 71 72 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDirectMusicCollection)) 73 *ret_iface = iface; 74 else if (IsEqualIID(riid, &IID_IDirectMusicObject)) 75 *ret_iface = &This->dmobj.IDirectMusicObject_iface; 76 else if (IsEqualIID(riid, &IID_IPersistStream)) 77 *ret_iface = &This->dmobj.IPersistStream_iface; 78 else 79 { 80 WARN("(%p/%p)->(%s, %p): not found\n", iface, This, debugstr_dmguid(riid), ret_iface); 81 return E_NOINTERFACE; 82 } 83 84 IUnknown_AddRef((IUnknown*)*ret_iface); 85 return S_OK; 86 } 87 88 static ULONG WINAPI IDirectMusicCollectionImpl_AddRef(IDirectMusicCollection *iface) 89 { 90 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface); 91 ULONG ref = InterlockedIncrement(&This->ref); 92 93 TRACE("(%p/%p)->(): new ref = %u\n", iface, This, ref); 94 95 return ref; 96 } 97 98 static ULONG WINAPI IDirectMusicCollectionImpl_Release(IDirectMusicCollection *iface) 99 { 100 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface); 101 ULONG ref = InterlockedDecrement(&This->ref); 102 103 TRACE("(%p/%p)->(): new ref = %u\n", iface, This, ref); 104 105 if (!ref) { 106 HeapFree(GetProcessHeap(), 0, This); 107 DMUSIC_UnlockModule(); 108 } 109 110 return ref; 111 } 112 113 /* IDirectMusicCollection Interface follows: */ 114 static HRESULT WINAPI IDirectMusicCollectionImpl_GetInstrument(IDirectMusicCollection *iface, 115 DWORD patch, IDirectMusicInstrument **instrument) 116 { 117 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface); 118 DMUS_PRIVATE_INSTRUMENTENTRY *inst_entry; 119 struct list *list_entry; 120 DWORD inst_patch; 121 122 TRACE("(%p/%p)->(%u, %p)\n", iface, This, patch, instrument); 123 124 LIST_FOR_EACH(list_entry, &This->Instruments) { 125 inst_entry = LIST_ENTRY(list_entry, DMUS_PRIVATE_INSTRUMENTENTRY, entry); 126 IDirectMusicInstrument_GetPatch(inst_entry->pInstrument, &inst_patch); 127 if (patch == inst_patch) { 128 *instrument = inst_entry->pInstrument; 129 IDirectMusicInstrument_AddRef(inst_entry->pInstrument); 130 IDirectMusicInstrumentImpl_CustomLoad(inst_entry->pInstrument, This->pStm); 131 TRACE(": returning instrument %p\n", *instrument); 132 return S_OK; 133 } 134 } 135 136 TRACE(": instrument not found\n"); 137 138 return DMUS_E_INVALIDPATCH; 139 } 140 141 static HRESULT WINAPI IDirectMusicCollectionImpl_EnumInstrument(IDirectMusicCollection *iface, 142 DWORD index, DWORD *patch, LPWSTR name, DWORD name_length) 143 { 144 IDirectMusicCollectionImpl *This = impl_from_IDirectMusicCollection(iface); 145 DWORD i = 0; 146 DMUS_PRIVATE_INSTRUMENTENTRY *inst_entry; 147 struct list *list_entry; 148 DWORD length; 149 150 TRACE("(%p/%p)->(%d, %p, %p, %d)\n", iface, This, index, patch, name, name_length); 151 152 LIST_FOR_EACH(list_entry, &This->Instruments) { 153 inst_entry = LIST_ENTRY(list_entry, DMUS_PRIVATE_INSTRUMENTENTRY, entry); 154 if (i == index) { 155 IDirectMusicInstrumentImpl *instrument = impl_from_IDirectMusicInstrument(inst_entry->pInstrument); 156 IDirectMusicInstrument_GetPatch(inst_entry->pInstrument, patch); 157 if (name) { 158 length = min(strlenW(instrument->wszName), name_length - 1); 159 memcpy(name, instrument->wszName, length * sizeof(WCHAR)); 160 name[length] = '\0'; 161 } 162 return S_OK; 163 } 164 i++; 165 } 166 167 return S_FALSE; 168 } 169 170 static const IDirectMusicCollectionVtbl DirectMusicCollection_Collection_Vtbl = { 171 IDirectMusicCollectionImpl_QueryInterface, 172 IDirectMusicCollectionImpl_AddRef, 173 IDirectMusicCollectionImpl_Release, 174 IDirectMusicCollectionImpl_GetInstrument, 175 IDirectMusicCollectionImpl_EnumInstrument 176 }; 177 178 /* IDirectMusicCollectionImpl IDirectMusicObject part: */ 179 static HRESULT read_from_stream(IStream *stream, void *data, ULONG size) 180 { 181 ULONG read; 182 HRESULT hr; 183 184 hr = IStream_Read(stream, data, size, &read); 185 if (FAILED(hr)) { 186 TRACE("IStream_Read failed: %08x\n", hr); 187 return hr; 188 } 189 if (read < size) { 190 TRACE("Didn't read full chunk: %u < %u\n", read, size); 191 return E_FAIL; 192 } 193 194 return S_OK; 195 } 196 197 static HRESULT WINAPI IDirectMusicObjectImpl_ParseDescriptor(IDirectMusicObject *iface, 198 IStream *stream, DMUS_OBJECTDESC *desc) 199 { 200 struct dmobject *This = impl_from_IDirectMusicObject(iface); 201 DMUS_PRIVATE_CHUNK chunk; 202 DWORD StreamSize, StreamCount, ListSize[1], ListCount[1]; 203 LARGE_INTEGER liMove; /* used when skipping chunks */ 204 HRESULT hr; 205 206 TRACE("(%p)->(%p, %p)\n", This, stream, desc); 207 208 /* FIXME: should this be determined from stream? */ 209 desc->dwValidData |= DMUS_OBJ_CLASS; 210 desc->guidClass = This->desc.guidClass; 211 212 hr = read_from_stream(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD)); 213 if (FAILED(hr)) 214 return hr; 215 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize); 216 217 if (chunk.fccID != FOURCC_RIFF) { 218 TRACE_(dmfile)(": unexpected chunk; loading failed)\n"); 219 liMove.QuadPart = chunk.dwSize; 220 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */ 221 return DMUS_E_INVALIDFILE; 222 } 223 224 hr = read_from_stream(stream, &chunk.fccID, sizeof(FOURCC)); 225 if (FAILED(hr)) 226 return hr; 227 TRACE_(dmfile)(": RIFF chunk of type %s", debugstr_fourcc(chunk.fccID)); 228 StreamSize = chunk.dwSize - sizeof(FOURCC); 229 230 if (chunk.fccID != FOURCC_DLS) { 231 TRACE_(dmfile)(": unexpected chunk; loading failed)\n"); 232 liMove.QuadPart = StreamSize; 233 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */ 234 return E_FAIL; 235 } 236 237 StreamCount = 0; 238 TRACE_(dmfile)(": collection form\n"); 239 240 do { 241 hr = read_from_stream(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD)); 242 if (FAILED(hr)) 243 return hr; 244 StreamCount += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize; 245 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize); 246 switch (chunk.fccID) { 247 case FOURCC_DLID: 248 TRACE_(dmfile)(": GUID chunk\n"); 249 desc->dwValidData |= DMUS_OBJ_OBJECT; 250 hr = read_from_stream(stream, &desc->guidObject, chunk.dwSize); 251 if (FAILED(hr)) 252 return hr; 253 break; 254 255 case DMUS_FOURCC_VERSION_CHUNK: 256 TRACE_(dmfile)(": version chunk\n"); 257 desc->dwValidData |= DMUS_OBJ_VERSION; 258 hr = read_from_stream(stream, &desc->vVersion, chunk.dwSize); 259 if (FAILED(hr)) 260 return hr; 261 break; 262 263 case DMUS_FOURCC_CATEGORY_CHUNK: 264 TRACE_(dmfile)(": category chunk\n"); 265 desc->dwValidData |= DMUS_OBJ_CATEGORY; 266 hr = read_from_stream(stream, desc->wszCategory, chunk.dwSize); 267 if (FAILED(hr)) 268 return hr; 269 break; 270 271 case FOURCC_LIST: 272 hr = read_from_stream(stream, &chunk.fccID, sizeof(FOURCC)); 273 if (FAILED(hr)) 274 return hr; 275 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(chunk.fccID)); 276 ListSize[0] = chunk.dwSize - sizeof(FOURCC); 277 ListCount[0] = 0; 278 switch (chunk.fccID) { 279 /* pure INFO list, such can be found in dls collections */ 280 case DMUS_FOURCC_INFO_LIST: 281 TRACE_(dmfile)(": INFO list\n"); 282 do { 283 hr = read_from_stream(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD)); 284 if (FAILED(hr)) 285 return hr; 286 ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize; 287 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize); 288 switch (chunk.fccID) { 289 case mmioFOURCC('I','N','A','M'): { 290 CHAR szName[DMUS_MAX_NAME]; 291 TRACE_(dmfile)(": name chunk\n"); 292 desc->dwValidData |= DMUS_OBJ_NAME; 293 hr = read_from_stream(stream, szName, chunk.dwSize); 294 if (FAILED(hr)) 295 return hr; 296 MultiByteToWideChar (CP_ACP, 0, szName, -1, desc->wszName, DMUS_MAX_NAME); 297 if (even_or_odd(chunk.dwSize)) { 298 ListCount[0]++; 299 liMove.QuadPart = 1; 300 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); 301 } 302 break; 303 } 304 305 case mmioFOURCC('I','A','R','T'): 306 TRACE_(dmfile)(": artist chunk (ignored)\n"); 307 if (even_or_odd(chunk.dwSize)) { 308 ListCount[0]++; 309 chunk.dwSize++; 310 } 311 liMove.QuadPart = chunk.dwSize; 312 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); 313 break; 314 315 case mmioFOURCC('I','C','O','P'): 316 TRACE_(dmfile)(": copyright chunk (ignored)\n"); 317 if (even_or_odd(chunk.dwSize)) { 318 ListCount[0]++; 319 chunk.dwSize++; 320 } 321 liMove.QuadPart = chunk.dwSize; 322 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); 323 break; 324 325 case mmioFOURCC('I','S','B','J'): 326 TRACE_(dmfile)(": subject chunk (ignored)\n"); 327 if (even_or_odd(chunk.dwSize)) { 328 ListCount[0]++; 329 chunk.dwSize++; 330 } 331 liMove.QuadPart = chunk.dwSize; 332 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); 333 break; 334 335 case mmioFOURCC('I','C','M','T'): 336 TRACE_(dmfile)(": comment chunk (ignored)\n"); 337 if (even_or_odd(chunk.dwSize)) { 338 ListCount[0]++; 339 chunk.dwSize++; 340 liMove.QuadPart = chunk.dwSize; 341 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); 342 break; 343 } 344 345 default: 346 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n"); 347 if (even_or_odd(chunk.dwSize)) { 348 ListCount[0] ++; 349 chunk.dwSize++; 350 } 351 liMove.QuadPart = chunk.dwSize; 352 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); 353 break; 354 } 355 TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]); 356 } while (ListCount[0] < ListSize[0]); 357 break; 358 359 default: 360 TRACE_(dmfile)(": unknown (skipping)\n"); 361 liMove.QuadPart = chunk.dwSize - sizeof(FOURCC); 362 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); 363 break; 364 } 365 break; 366 367 default: 368 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n"); 369 liMove.QuadPart = chunk.dwSize; 370 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); 371 break; 372 } 373 TRACE_(dmfile)(": StreamCount[0] = %d < StreamSize[0] = %d\n", StreamCount, StreamSize); 374 } while (StreamCount < StreamSize); 375 376 TRACE_(dmfile)(": reading finished\n"); 377 378 if (TRACE_ON(dmusic)) { 379 TRACE("Returning descriptor:\n"); 380 dump_DMUS_OBJECTDESC(desc); 381 } 382 383 return S_OK; 384 } 385 386 static const IDirectMusicObjectVtbl dmobject_vtbl = { 387 dmobj_IDirectMusicObject_QueryInterface, 388 dmobj_IDirectMusicObject_AddRef, 389 dmobj_IDirectMusicObject_Release, 390 dmobj_IDirectMusicObject_GetDescriptor, 391 dmobj_IDirectMusicObject_SetDescriptor, 392 IDirectMusicObjectImpl_ParseDescriptor 393 }; 394 395 /* IDirectMusicCollectionImpl IPersistStream part: */ 396 static HRESULT WINAPI IPersistStreamImpl_Load(IPersistStream *iface, 397 IStream *stream) 398 { 399 IDirectMusicCollectionImpl *This = impl_from_IPersistStream(iface); 400 DMUS_PRIVATE_CHUNK chunk; 401 DWORD StreamSize, StreamCount, ListSize[2], ListCount[2]; 402 LARGE_INTEGER liMove; /* used when skipping chunks */ 403 ULARGE_INTEGER dlibCollectionPosition, dlibInstrumentPosition, dlibWavePoolPosition; 404 405 IStream_AddRef(stream); /* add count for later references */ 406 liMove.QuadPart = 0; 407 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, &dlibCollectionPosition); /* store offset, in case it'll be needed later */ 408 This->liCollectionPosition.QuadPart = dlibCollectionPosition.QuadPart; 409 This->pStm = stream; 410 411 IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL); 412 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize); 413 414 if (chunk.fccID != FOURCC_RIFF) { 415 TRACE_(dmfile)(": unexpected chunk; loading failed)\n"); 416 liMove.QuadPart = chunk.dwSize; 417 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */ 418 return E_FAIL; 419 } 420 421 IStream_Read(stream, &chunk.fccID, sizeof(FOURCC), NULL); 422 TRACE_(dmfile)(": RIFF chunk of type %s", debugstr_fourcc(chunk.fccID)); 423 StreamSize = chunk.dwSize - sizeof(FOURCC); 424 StreamCount = 0; 425 426 if (chunk.fccID != FOURCC_DLS) { 427 TRACE_(dmfile)(": unexpected chunk; loading failed)\n"); 428 liMove.QuadPart = StreamSize; 429 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); /* skip the rest of the chunk */ 430 return E_FAIL; 431 } 432 433 TRACE_(dmfile)(": collection form\n"); 434 do { 435 IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL); 436 StreamCount += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize; 437 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize); 438 switch (chunk.fccID) { 439 case FOURCC_COLH: { 440 TRACE_(dmfile)(": collection header chunk\n"); 441 This->pHeader = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, chunk.dwSize); 442 IStream_Read(stream, This->pHeader, chunk.dwSize, NULL); 443 break; 444 } 445 case FOURCC_DLID: { 446 TRACE_(dmfile)(": DLID (GUID) chunk\n"); 447 This->dmobj.desc.dwValidData |= DMUS_OBJ_OBJECT; 448 IStream_Read(stream, &This->dmobj.desc.guidObject, chunk.dwSize, NULL); 449 break; 450 } 451 case FOURCC_VERS: { 452 TRACE_(dmfile)(": version chunk\n"); 453 This->dmobj.desc.dwValidData |= DMUS_OBJ_VERSION; 454 IStream_Read(stream, &This->dmobj.desc.vVersion, chunk.dwSize, NULL); 455 break; 456 } 457 case FOURCC_PTBL: { 458 TRACE_(dmfile)(": pool table chunk\n"); 459 This->pPoolTable = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(POOLTABLE)); 460 IStream_Read(stream, This->pPoolTable, sizeof(POOLTABLE), NULL); 461 chunk.dwSize -= sizeof(POOLTABLE); 462 This->pPoolCues = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->pPoolTable->cCues * sizeof(POOLCUE)); 463 IStream_Read(stream, This->pPoolCues, chunk.dwSize, NULL); 464 break; 465 } 466 case FOURCC_LIST: { 467 IStream_Read(stream, &chunk.fccID, sizeof(FOURCC), NULL); 468 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(chunk.fccID)); 469 ListSize[0] = chunk.dwSize - sizeof(FOURCC); 470 ListCount[0] = 0; 471 switch (chunk.fccID) { 472 case DMUS_FOURCC_INFO_LIST: { 473 TRACE_(dmfile)(": INFO list\n"); 474 do { 475 IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL); 476 ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize; 477 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize); 478 switch (chunk.fccID) { 479 case mmioFOURCC('I','N','A','M'): { 480 CHAR szName[DMUS_MAX_NAME]; 481 TRACE_(dmfile)(": name chunk\n"); 482 This->dmobj.desc.dwValidData |= DMUS_OBJ_NAME; 483 IStream_Read(stream, szName, chunk.dwSize, NULL); 484 MultiByteToWideChar(CP_ACP, 0, szName, -1, This->dmobj.desc.wszName, DMUS_MAX_NAME); 485 if (even_or_odd(chunk.dwSize)) { 486 ListCount[0]++; 487 liMove.QuadPart = 1; 488 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); 489 } 490 break; 491 } 492 case mmioFOURCC('I','A','R','T'): { 493 TRACE_(dmfile)(": artist chunk (ignored)\n"); 494 if (even_or_odd(chunk.dwSize)) { 495 ListCount[0]++; 496 chunk.dwSize++; 497 } 498 liMove.QuadPart = chunk.dwSize; 499 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); 500 break; 501 } 502 case mmioFOURCC('I','C','O','P'): { 503 TRACE_(dmfile)(": copyright chunk\n"); 504 This->szCopyright = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, chunk.dwSize); 505 IStream_Read(stream, This->szCopyright, chunk.dwSize, NULL); 506 if (even_or_odd(chunk.dwSize)) { 507 ListCount[0]++; 508 liMove.QuadPart = 1; 509 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); 510 } 511 break; 512 } 513 case mmioFOURCC('I','S','B','J'): { 514 TRACE_(dmfile)(": subject chunk (ignored)\n"); 515 if (even_or_odd(chunk.dwSize)) { 516 ListCount[0]++; 517 chunk.dwSize++; 518 } 519 liMove.QuadPart = chunk.dwSize; 520 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); 521 break; 522 } 523 case mmioFOURCC('I','C','M','T'): { 524 TRACE_(dmfile)(": comment chunk (ignored)\n"); 525 if (even_or_odd(chunk.dwSize)) { 526 ListCount[0]++; 527 chunk.dwSize++; 528 } 529 liMove.QuadPart = chunk.dwSize; 530 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); 531 break; 532 } 533 default: { 534 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n"); 535 if (even_or_odd(chunk.dwSize)) { 536 ListCount[0]++; 537 chunk.dwSize++; 538 } 539 liMove.QuadPart = chunk.dwSize; 540 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); 541 break; 542 } 543 } 544 TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]); 545 } while (ListCount[0] < ListSize[0]); 546 break; 547 } 548 case FOURCC_WVPL: { 549 TRACE_(dmfile)(": wave pool list (mark & skip)\n"); 550 liMove.QuadPart = 0; 551 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, &dlibWavePoolPosition); /* store position */ 552 This->liWavePoolTablePosition.QuadPart = dlibWavePoolPosition.QuadPart; 553 liMove.QuadPart = chunk.dwSize - sizeof(FOURCC); 554 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); 555 break; 556 } 557 case FOURCC_LINS: { 558 TRACE_(dmfile)(": instruments list\n"); 559 do { 560 IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL); 561 ListCount[0] += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize; 562 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize); 563 switch (chunk.fccID) { 564 case FOURCC_LIST: { 565 IStream_Read(stream, &chunk.fccID, sizeof(FOURCC), NULL); 566 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(chunk.fccID)); 567 ListSize[1] = chunk.dwSize - sizeof(FOURCC); 568 ListCount[1] = 0; 569 switch (chunk.fccID) { 570 case FOURCC_INS: { 571 LPDMUS_PRIVATE_INSTRUMENTENTRY new_instrument = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DMUS_PRIVATE_INSTRUMENTENTRY)); 572 TRACE_(dmfile)(": instrument list\n"); 573 /* Only way to create this one... even M$ does it discretely */ 574 DMUSIC_CreateDirectMusicInstrumentImpl(&IID_IDirectMusicInstrument, (void**)&new_instrument->pInstrument, NULL); 575 { 576 IDirectMusicInstrumentImpl *instrument = impl_from_IDirectMusicInstrument(new_instrument->pInstrument); 577 /* Store offset and length, they will be needed when loading the instrument */ 578 liMove.QuadPart = 0; 579 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, &dlibInstrumentPosition); 580 instrument->liInstrumentPosition.QuadPart = dlibInstrumentPosition.QuadPart; 581 instrument->length = ListSize[1]; 582 do { 583 IStream_Read(stream, &chunk, sizeof(FOURCC) + sizeof(DWORD), NULL); 584 ListCount[1] += sizeof(FOURCC) + sizeof(DWORD) + chunk.dwSize; 585 TRACE_(dmfile)(": %s chunk (size = 0x%04x)", debugstr_fourcc(chunk.fccID), chunk.dwSize); 586 switch (chunk.fccID) { 587 case FOURCC_INSH: { 588 TRACE_(dmfile)(": instrument header chunk\n"); 589 IStream_Read(stream, &instrument->header, chunk.dwSize, NULL); 590 break; 591 } 592 case FOURCC_DLID: { 593 TRACE_(dmfile)(": DLID (GUID) chunk\n"); 594 IStream_Read(stream, &instrument->id, chunk.dwSize, NULL); 595 break; 596 } 597 case FOURCC_LIST: { 598 IStream_Read(stream, &chunk.fccID, sizeof(FOURCC), NULL); 599 TRACE_(dmfile)(": LIST chunk of type %s", debugstr_fourcc(chunk.fccID)); 600 switch (chunk.fccID) { 601 default: { 602 TRACE_(dmfile)(": unknown (skipping)\n"); 603 liMove.QuadPart = chunk.dwSize - sizeof(FOURCC); 604 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); 605 break; 606 } 607 } 608 break; 609 } 610 default: { 611 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n"); 612 liMove.QuadPart = chunk.dwSize; 613 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); 614 break; 615 } 616 } 617 TRACE_(dmfile)(": ListCount[1] = %d < ListSize[1] = %d\n", ListCount[1], ListSize[1]); 618 } while (ListCount[1] < ListSize[1]); 619 /* DEBUG: dumps whole instrument object tree: */ 620 if (TRACE_ON(dmusic)) { 621 TRACE("*** IDirectMusicInstrument (%p) ***\n", instrument); 622 if (!IsEqualGUID(&instrument->id, &GUID_NULL)) 623 TRACE(" - GUID = %s\n", debugstr_dmguid(&instrument->id)); 624 TRACE(" - Instrument header:\n"); 625 TRACE(" - cRegions: %d\n", instrument->header.cRegions); 626 TRACE(" - Locale:\n"); 627 TRACE(" - ulBank: %d\n", instrument->header.Locale.ulBank); 628 TRACE(" - ulInstrument: %d\n", instrument->header.Locale.ulInstrument); 629 TRACE(" => dwPatch: %d\n", MIDILOCALE2Patch(&instrument->header.Locale)); 630 } 631 list_add_tail(&This->Instruments, &new_instrument->entry); 632 } 633 break; 634 } 635 } 636 break; 637 } 638 default: { 639 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n"); 640 liMove.QuadPart = chunk.dwSize; 641 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); 642 break; 643 } 644 } 645 TRACE_(dmfile)(": ListCount[0] = %d < ListSize[0] = %d\n", ListCount[0], ListSize[0]); 646 } while (ListCount[0] < ListSize[0]); 647 break; 648 } 649 default: { 650 TRACE_(dmfile)(": unknown (skipping)\n"); 651 liMove.QuadPart = chunk.dwSize - sizeof(FOURCC); 652 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); 653 break; 654 } 655 } 656 break; 657 } 658 default: { 659 TRACE_(dmfile)(": unknown chunk (irrelevant & skipping)\n"); 660 liMove.QuadPart = chunk.dwSize; 661 IStream_Seek(stream, liMove, STREAM_SEEK_CUR, NULL); 662 break; 663 } 664 } 665 TRACE_(dmfile)(": StreamCount = %d < StreamSize = %d\n", StreamCount, StreamSize); 666 } while (StreamCount < StreamSize); 667 668 TRACE_(dmfile)(": reading finished\n"); 669 670 671 /* DEBUG: dumps whole collection object tree: */ 672 if (TRACE_ON(dmusic)) { 673 int r = 0; 674 DMUS_PRIVATE_INSTRUMENTENTRY *tmpEntry; 675 struct list *listEntry; 676 677 TRACE("*** IDirectMusicCollection (%p) ***\n", &This->IDirectMusicCollection_iface); 678 if (This->dmobj.desc.dwValidData & DMUS_OBJ_OBJECT) 679 TRACE(" - GUID = %s\n", debugstr_dmguid(&This->dmobj.desc.guidObject)); 680 if (This->dmobj.desc.dwValidData & DMUS_OBJ_VERSION) 681 TRACE(" - Version = %i,%i,%i,%i\n", (This->dmobj.desc.vVersion.dwVersionMS >> 8) & 0x0000FFFF, This->dmobj.desc.vVersion.dwVersionMS & 0x0000FFFF, 682 (This->dmobj.desc.vVersion.dwVersionLS >> 8) & 0x0000FFFF, This->dmobj.desc.vVersion.dwVersionLS & 0x0000FFFF); 683 if (This->dmobj.desc.dwValidData & DMUS_OBJ_NAME) 684 TRACE(" - Name = %s\n", debugstr_w(This->dmobj.desc.wszName)); 685 686 TRACE(" - Collection header:\n"); 687 TRACE(" - cInstruments: %d\n", This->pHeader->cInstruments); 688 TRACE(" - Instruments:\n"); 689 690 LIST_FOR_EACH(listEntry, &This->Instruments) { 691 tmpEntry = LIST_ENTRY( listEntry, DMUS_PRIVATE_INSTRUMENTENTRY, entry ); 692 TRACE(" - Instrument[%i]: %p\n", r, tmpEntry->pInstrument); 693 r++; 694 } 695 } 696 697 return S_OK; 698 } 699 700 static const IPersistStreamVtbl persiststream_vtbl = { 701 dmobj_IPersistStream_QueryInterface, 702 dmobj_IPersistStream_AddRef, 703 dmobj_IPersistStream_Release, 704 unimpl_IPersistStream_GetClassID, 705 unimpl_IPersistStream_IsDirty, 706 IPersistStreamImpl_Load, 707 unimpl_IPersistStream_Save, 708 unimpl_IPersistStream_GetSizeMax 709 }; 710 711 712 HRESULT WINAPI DMUSIC_CreateDirectMusicCollectionImpl(LPCGUID lpcGUID, LPVOID* ppobj, LPUNKNOWN pUnkOuter) 713 { 714 IDirectMusicCollectionImpl* obj; 715 HRESULT hr; 716 717 *ppobj = NULL; 718 if (pUnkOuter) 719 return CLASS_E_NOAGGREGATION; 720 721 obj = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectMusicCollectionImpl)); 722 if (!obj) 723 return E_OUTOFMEMORY; 724 725 obj->IDirectMusicCollection_iface.lpVtbl = &DirectMusicCollection_Collection_Vtbl; 726 obj->ref = 1; 727 dmobject_init(&obj->dmobj, &CLSID_DirectMusicCollection, 728 (IUnknown*)&obj->IDirectMusicCollection_iface); 729 obj->dmobj.IDirectMusicObject_iface.lpVtbl = &dmobject_vtbl; 730 obj->dmobj.IPersistStream_iface.lpVtbl = &persiststream_vtbl; 731 732 list_init (&obj->Instruments); 733 734 DMUSIC_LockModule(); 735 hr = IDirectMusicCollection_QueryInterface(&obj->IDirectMusicCollection_iface, lpcGUID, ppobj); 736 IDirectMusicCollection_Release(&obj->IDirectMusicCollection_iface); 737 738 return hr; 739 } 740