Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1054 lines
32 KiB

  1. // Copyright (c) 1998-2001 Microsoft Corporation
  2. // DMGraph.cpp : Implementation of CGraph
  3. #include "dmime.h"
  4. #include "DMGraph.h"
  5. #include "dmusicc.h"
  6. #include "dmusici.h"
  7. #include "dmusicf.h"
  8. #include "..\shared\dmstrm.h"
  9. #include "..\shared\validp.h"
  10. #include "dls1.h"
  11. #include "debug.h"
  12. #include "..\shared\Validate.h"
  13. #include <strsafe.h>
  14. #define ASSERT assert
  15. CGraph::CGraph()
  16. {
  17. m_cRef = 1;
  18. memset(&m_guidObject,0,sizeof(m_guidObject));
  19. m_dwValidData = DMUS_OBJ_CLASS; // upon creation, only this data is valid
  20. memset(&m_ftDate, 0,sizeof(m_ftDate));
  21. memset(&m_vVersion, 0,sizeof(m_vVersion));
  22. memset(m_wszName, 0, sizeof(WCHAR) * DMUS_MAX_NAME);
  23. memset(m_wszCategory, 0, sizeof(WCHAR) * DMUS_MAX_CATEGORY);
  24. memset(m_wszFileName, 0, sizeof(WCHAR) * DMUS_MAX_FILENAME);
  25. InitializeCriticalSection(&m_CrSec);
  26. InterlockedIncrement(&g_cComponent);
  27. }
  28. CGraph::~CGraph()
  29. {
  30. Shutdown(); // shouldn't be needed, but doesn't hurt
  31. DeleteCriticalSection(&m_CrSec);
  32. InterlockedDecrement(&g_cComponent);
  33. }
  34. STDMETHODIMP CGraph::QueryInterface(
  35. const IID &iid, // @parm Interface to query for
  36. void **ppv) // @parm The requested interface will be returned here
  37. {
  38. V_INAME(CGraph::QueryInterface);
  39. V_PTRPTR_WRITE(ppv);
  40. V_REFGUID(iid);
  41. if (iid == IID_IUnknown || iid == IID_IDirectMusicGraph || iid == IID_IDirectMusicGraph8)
  42. {
  43. *ppv = static_cast<IDirectMusicGraph8*>(this);
  44. }
  45. else if (iid == IID_CGraph)
  46. {
  47. *ppv = static_cast<CGraph*>(this);
  48. }
  49. else if (iid == IID_IDirectMusicObject)
  50. {
  51. *ppv = static_cast<IDirectMusicObject*>(this);
  52. }
  53. else if (iid == IID_IPersistStream)
  54. {
  55. *ppv = static_cast<IPersistStream*>(this);
  56. }
  57. else if (iid == IID_IGraphClone)
  58. {
  59. *ppv = static_cast<IGraphClone*>(this);
  60. }
  61. else
  62. {
  63. *ppv = NULL;
  64. Trace(4,"Warning: Request to query unknown interface on ToolGraph object\n");
  65. return E_NOINTERFACE;
  66. }
  67. reinterpret_cast<IUnknown*>(this)->AddRef();
  68. return S_OK;
  69. }
  70. // @method:(INTERNAL) HRESULT | IDirectMusicGraph | AddRef | Standard AddRef implementation for <i IDirectMusicGraph>
  71. //
  72. // @rdesc Returns the new reference count for this object.
  73. //
  74. STDMETHODIMP_(ULONG) CGraph::AddRef()
  75. {
  76. return InterlockedIncrement(&m_cRef);
  77. }
  78. // @method:(INTERNAL) HRESULT | IDirectMusicGraph | Release | Standard Release implementation for <i IDirectMusicGraph>
  79. //
  80. // @rdesc Returns the new reference count for this object.
  81. //
  82. STDMETHODIMP_(ULONG) CGraph::Release()
  83. {
  84. if (!InterlockedDecrement(&m_cRef))
  85. {
  86. delete this;
  87. return 0;
  88. }
  89. return m_cRef;
  90. }
  91. /*
  92. Made internal 9/25/98
  93. method HRESULT | IDirectMusicGraph | Shutdown |
  94. Shuts down the graph. This must be called when the graph is no longer needed,
  95. in order to release the tools and other memory. A call to Release is not
  96. sufficient, because there is circular referencing between the graph and the tools.
  97. However, only the segment, performance, or whatever owns the graph
  98. should call this function.
  99. rvalue S_OK | Success.
  100. rvalue S_FALSE | Success, but didn't need to do anything.
  101. */
  102. HRESULT STDMETHODCALLTYPE CGraph::Shutdown()
  103. {
  104. // release all Tools
  105. CToolRef* pObj;
  106. HRESULT hr = S_OK;
  107. EnterCriticalSection(&m_CrSec);
  108. if( IsEmpty() )
  109. {
  110. hr = S_FALSE;
  111. }
  112. else
  113. {
  114. while( pObj = RemoveHead() )
  115. {
  116. delete pObj;
  117. }
  118. }
  119. LeaveCriticalSection(&m_CrSec);
  120. return hr;
  121. }
  122. HRESULT CGraph::InsertTool(
  123. IDirectMusicTool *pTool,
  124. DWORD *pdwPChannels,
  125. DWORD cPChannels,
  126. LONG lIndex,
  127. GUID *pguidClassID)
  128. {
  129. HRESULT hr = S_OK;
  130. EnterCriticalSection(&m_CrSec);
  131. CToolRef* pToolRef;
  132. // make sure that this Tool instance isn't already in the Graph
  133. for( pToolRef = GetHead(); pToolRef; pToolRef = pToolRef->GetNext() )
  134. {
  135. if( pTool == pToolRef->m_pTool )
  136. {
  137. LeaveCriticalSection(&m_CrSec);
  138. Trace(1,"Error: Multiple install of the same tool in a graph\n");
  139. return DMUS_E_ALREADY_EXISTS;
  140. }
  141. }
  142. // insert this Tool instance into the Graph
  143. pToolRef = new CToolRef;
  144. if( pToolRef )
  145. {
  146. DWORD dwTemp;
  147. DWORD* pdwArray = NULL;
  148. pToolRef->m_pTool = pTool;
  149. pTool->AddRef();
  150. pTool->Init(this);
  151. dwTemp = 0;
  152. IDirectMusicTool8 *pTool8;
  153. if (SUCCEEDED(pTool->QueryInterface(IID_IDirectMusicTool8,(void **) &pTool8)))
  154. {
  155. pToolRef->m_fSupportsClone = TRUE;
  156. pTool8->Release();
  157. }
  158. if (pguidClassID)
  159. {
  160. pToolRef->m_guidClassID = *pguidClassID;
  161. }
  162. else
  163. {
  164. IPersistStream *pPersist;
  165. if (SUCCEEDED(pTool->QueryInterface(IID_IPersistStream,(void **) &pPersist)))
  166. {
  167. pPersist->GetClassID(&pToolRef->m_guidClassID);
  168. pPersist->Release();
  169. }
  170. }
  171. pTool->GetMsgDeliveryType(&dwTemp);
  172. if( (dwTemp != DMUS_PMSGF_TOOL_IMMEDIATE) && (dwTemp != DMUS_PMSGF_TOOL_QUEUE) && (dwTemp != DMUS_PMSGF_TOOL_ATTIME) )
  173. {
  174. dwTemp = DMUS_PMSGF_TOOL_IMMEDIATE;
  175. }
  176. pToolRef->m_dwQueue = dwTemp;
  177. if( FAILED( pTool->GetMediaTypeArraySize(&dwTemp)))
  178. {
  179. dwTemp = 0;
  180. }
  181. pToolRef->m_dwMTArraySize = dwTemp;
  182. if( dwTemp )
  183. {
  184. pdwArray = new DWORD[dwTemp];
  185. if( pdwArray )
  186. {
  187. HRESULT hrTemp = pTool->GetMediaTypes( &pdwArray, dwTemp );
  188. if( hrTemp == E_NOTIMPL )
  189. {
  190. delete [] pdwArray;
  191. pToolRef->m_dwMTArraySize = 0;
  192. }
  193. else
  194. {
  195. pToolRef->m_pdwMediaTypes = pdwArray;
  196. }
  197. }
  198. else
  199. {
  200. delete pToolRef;
  201. LeaveCriticalSection(&m_CrSec);
  202. return E_OUTOFMEMORY;
  203. }
  204. }
  205. if( pdwPChannels )
  206. {
  207. pToolRef->m_pdwPChannels = new DWORD[cPChannels];
  208. if( pToolRef->m_pdwPChannels )
  209. {
  210. memcpy( pToolRef->m_pdwPChannels, pdwPChannels, sizeof(DWORD) * cPChannels );
  211. pToolRef->m_dwPCArraySize = cPChannels;
  212. }
  213. else
  214. {
  215. delete pToolRef;
  216. LeaveCriticalSection(&m_CrSec);
  217. return E_OUTOFMEMORY;
  218. }
  219. }
  220. if (lIndex < 0)
  221. {
  222. lIndex += AList::GetCount(); // Make index be offset from end.
  223. }
  224. CToolRef *pNext = GetItem(lIndex);
  225. if (pNext)
  226. {
  227. InsertBefore(pNext,pToolRef);
  228. }
  229. else
  230. {
  231. AList::AddTail(pToolRef);
  232. }
  233. }
  234. else
  235. {
  236. hr = E_OUTOFMEMORY;
  237. }
  238. LeaveCriticalSection(&m_CrSec);
  239. return hr;
  240. }
  241. HRESULT STDMETHODCALLTYPE CGraph::InsertTool(
  242. IDirectMusicTool *pTool, // @parm The Tool to insert.
  243. DWORD *pdwPChannels, // @parm An array of which PChannels to place the tool in. These are
  244. // id's which are converted to MIDI Channel + Port on output. If the
  245. // tool accepts messages on all PChannels, this is NULL. <p cPChannels>
  246. // is the count of how many this array points to.
  247. DWORD cPChannels, // @parm Count of how many PChannels are pointed to by <p pdwPChannels>.
  248. LONG lIndex) // @parm At what position to place the tool. This is an index from either the start
  249. // of the current tool list or, working backwards from the end (in which case, it is
  250. // a negative number.) If <p lIndex> is out of range, the Tool will be placed at
  251. // the very beginning or end of the Tool list. 0 is the beginning. To place a Tool
  252. // at the end of the list, use a number for <p lIndex> that is larger than the number
  253. // of tools in the current tool list.
  254. {
  255. V_INAME(IDirectMusicGraph::InsertTool);
  256. V_INTERFACE(pTool);
  257. V_BUFPTR_READ_OPT(pdwPChannels, sizeof(DWORD) * cPChannels);
  258. return InsertTool(pTool,pdwPChannels,cPChannels,lIndex,NULL);
  259. }
  260. HRESULT CGraph::GetObjectInPath( DWORD dwPChannel,REFGUID guidObject,
  261. DWORD dwIndex,REFGUID iidInterface, void ** ppObject)
  262. {
  263. V_INAME(IDirectMusicGraph::GetObjectInPath);
  264. V_PTRPTR_WRITE(ppObject);
  265. HRESULT hr = DMUS_E_NOT_FOUND;
  266. CToolRef* pPlace;
  267. if( !IsEmpty() )
  268. {
  269. pPlace = NULL;
  270. // search for the tool
  271. EnterCriticalSection(&m_CrSec);
  272. for( pPlace = GetHead(); pPlace;
  273. pPlace = pPlace->GetNext() )
  274. {
  275. if ((guidObject == pPlace->m_guidClassID) || (guidObject == GUID_All_Objects))
  276. {
  277. BOOL fFound = (!pPlace->m_pdwPChannels || (dwPChannel >= DMUS_PCHANNEL_ALL));
  278. if( !fFound )
  279. {
  280. DWORD cCount;
  281. // scan through the array of PChannels to see if this one
  282. // supports dwPChannel
  283. for( cCount = 0; cCount < pPlace->m_dwPCArraySize; cCount++)
  284. {
  285. if( dwPChannel == pPlace->m_pdwPChannels[cCount] )
  286. {
  287. fFound = TRUE;
  288. // yep, it supports it
  289. break;
  290. }
  291. }
  292. }
  293. if (fFound)
  294. {
  295. if (!dwIndex)
  296. {
  297. break;
  298. }
  299. else
  300. {
  301. dwIndex--;
  302. }
  303. }
  304. }
  305. }
  306. if( pPlace )
  307. {
  308. hr = pPlace->m_pTool->QueryInterface(iidInterface,ppObject);
  309. }
  310. LeaveCriticalSection(&m_CrSec);
  311. }
  312. #ifdef DBG
  313. if (hr == DMUS_E_NOT_FOUND)
  314. {
  315. Trace(1,"Error: Requested Tool not found in Graph\n");
  316. }
  317. #endif
  318. return hr;
  319. }
  320. /*
  321. @method HRESULT | IDirectMusicGraph | GetTool |
  322. Returns the Tool at the specified index.
  323. @rvalue DMUS_E_NOT_FOUND | Unable to find a Tool at the position described.
  324. @rvalue E_POINTER | ppTool is NULL or invalid.
  325. @rvalue S_OK | Success.
  326. @comm The retrieved tool is AddRef'd by this call, so be sure to Release it.
  327. */
  328. HRESULT STDMETHODCALLTYPE CGraph::GetTool(
  329. DWORD dwIndex, // @parm The index, from the beginning and starting at 0,
  330. // at which to retrieve the Tool from the Graph.
  331. IDirectMusicTool **ppTool) // @parm The <i IDirectMusicTool> pointer to use
  332. // for returning the requested tool.
  333. {
  334. V_INAME(IDirectMusicGraph::GetTool);
  335. V_PTRPTR_WRITE(ppTool);
  336. CToolRef* pPlace;
  337. HRESULT hr = S_OK;
  338. if( IsEmpty() )
  339. {
  340. Trace(1,"Error: GetTool failed because the Tool Graph is empty\n");
  341. return DMUS_E_NOT_FOUND;
  342. }
  343. pPlace = NULL;
  344. // search for the indexed tool
  345. EnterCriticalSection(&m_CrSec);
  346. for( pPlace = GetHead(); ( dwIndex > 0 ) && pPlace;
  347. pPlace = pPlace->GetNext() )
  348. {
  349. dwIndex--;
  350. }
  351. if( NULL == pPlace )
  352. {
  353. hr = DMUS_E_NOT_FOUND;
  354. }
  355. else
  356. {
  357. *ppTool = pPlace->m_pTool;
  358. (*ppTool)->AddRef();
  359. }
  360. LeaveCriticalSection(&m_CrSec);
  361. return hr;
  362. }
  363. /*
  364. @method HRESULT | IDirectMusicGraph | RemoveTool |
  365. Removes the Tool from the Graph.
  366. @rvalue DMUS_E_NOT_FOUND | The specified Tool is not in the Graph.
  367. @rvalue E_POINTER | pTool is NULL or invalid.
  368. @rvalue S_OK | Success.
  369. @comm The Tool is removed from the Graph, and the Graph's reference on the Tool
  370. object is released.
  371. */
  372. HRESULT STDMETHODCALLTYPE CGraph::RemoveTool(
  373. IDirectMusicTool *pTool) // @parm The <i IDirectMusicTool> pointer of the Tool to remove.
  374. {
  375. V_INAME(IDirectMusicGraph::RemoveTool);
  376. V_INTERFACE(pTool);
  377. CToolRef* pPlace;
  378. HRESULT hr = S_OK;
  379. EnterCriticalSection(&m_CrSec);
  380. // search for the tool
  381. for( pPlace = GetHead(); pPlace; pPlace = pPlace->GetNext() )
  382. {
  383. if( pPlace->m_pTool == pTool )
  384. break;
  385. }
  386. if( NULL == pPlace )
  387. {
  388. Trace(1,"Error: RemoveTool - Tool not in Graph.\n");
  389. hr = DMUS_E_NOT_FOUND;
  390. }
  391. else
  392. {
  393. AList::Remove(pPlace);
  394. delete pPlace;
  395. }
  396. LeaveCriticalSection(&m_CrSec);
  397. return hr;
  398. }
  399. STDMETHODIMP CGraph::Clone(IDirectMusicGraph **ppGraph)
  400. {
  401. V_INAME(IDirectMusicGraph::Clone);
  402. V_PTRPTR_WRITE(ppGraph);
  403. HRESULT hr = E_OUTOFMEMORY;
  404. EnterCriticalSection(&m_CrSec);
  405. CGraph *pNew = new CGraph;
  406. if (pNew)
  407. {
  408. pNew->m_dwValidData = m_dwValidData;
  409. pNew->m_ftDate = m_ftDate;
  410. pNew->m_guidObject = m_guidObject;
  411. pNew->m_vVersion = m_vVersion;
  412. StringCchCopyW(pNew->m_wszCategory, DMUS_MAX_CATEGORY, m_wszCategory);
  413. StringCchCopyW(pNew->m_wszFileName, DMUS_MAX_FILENAME, m_wszFileName);
  414. StringCchCopyW(pNew->m_wszName, DMUS_MAX_NAME, m_wszName);
  415. CToolRef *pSource = GetHead();
  416. CToolRef *pDest;
  417. for (;pSource;pSource = pSource->GetNext())
  418. {
  419. pDest = new CToolRef;
  420. if (pDest)
  421. {
  422. pNew->AList::AddTail(pDest);
  423. pDest->m_dwMTArraySize = pSource->m_dwMTArraySize;
  424. pDest->m_dwPCArraySize = pSource->m_dwPCArraySize;
  425. pDest->m_dwQueue = pSource->m_dwQueue;
  426. pDest->m_fSupportsClone = pSource->m_fSupportsClone;
  427. pDest->m_guidClassID = pSource->m_guidClassID;
  428. if (pSource->m_dwMTArraySize)
  429. {
  430. pDest->m_pdwMediaTypes = new DWORD[pSource->m_dwMTArraySize];
  431. if (pDest->m_pdwMediaTypes)
  432. {
  433. memcpy(pDest->m_pdwMediaTypes,pSource->m_pdwMediaTypes,
  434. sizeof(DWORD)*pDest->m_dwMTArraySize);
  435. }
  436. else
  437. {
  438. pDest->m_dwMTArraySize = 0;
  439. }
  440. }
  441. else
  442. {
  443. pDest->m_pdwMediaTypes = NULL;
  444. }
  445. if (pSource->m_dwPCArraySize)
  446. {
  447. pDest->m_pdwPChannels = new DWORD[pSource->m_dwPCArraySize];
  448. if (pDest->m_pdwPChannels)
  449. {
  450. memcpy(pDest->m_pdwPChannels,pSource->m_pdwPChannels,
  451. sizeof(DWORD)*pDest->m_dwPCArraySize);
  452. }
  453. else
  454. {
  455. pDest->m_dwPCArraySize = 0;
  456. }
  457. }
  458. else
  459. {
  460. pDest->m_pdwPChannels = NULL;
  461. }
  462. if (pSource->m_pTool)
  463. {
  464. if (pDest->m_fSupportsClone)
  465. {
  466. IDirectMusicTool8 *pTool8 = (IDirectMusicTool8 *) pSource->m_pTool;
  467. pTool8->Clone(&pDest->m_pTool);
  468. }
  469. else
  470. {
  471. pDest->m_pTool = pSource->m_pTool;
  472. pDest->m_pTool->AddRef();
  473. }
  474. }
  475. }
  476. else
  477. {
  478. delete pNew;
  479. pNew = NULL;
  480. break;
  481. }
  482. }
  483. }
  484. *ppGraph = (IDirectMusicGraph *) pNew;
  485. if (pNew) hr = S_OK;
  486. LeaveCriticalSection(&m_CrSec);
  487. return hr;
  488. }
  489. // returns TRUE if dwType is supported by pToolRef
  490. inline BOOL CGraph::CheckType( DWORD dwType, CToolRef* pToolRef )
  491. {
  492. BOOL fReturn = FALSE;
  493. if( pToolRef->m_dwMTArraySize == 0 )
  494. {
  495. fReturn = TRUE; // supports all types
  496. }
  497. else
  498. {
  499. DWORD dw;
  500. ASSERT( pToolRef->m_pdwMediaTypes );
  501. for( dw = 0; dw < pToolRef->m_dwMTArraySize; dw++ )
  502. {
  503. if( dwType == pToolRef->m_pdwMediaTypes[dw] )
  504. {
  505. fReturn = TRUE;
  506. break;
  507. }
  508. }
  509. }
  510. return fReturn;
  511. }
  512. HRESULT STDMETHODCALLTYPE CGraph::StampPMsg(
  513. DMUS_PMSG* pPMsg) // @parm The message to stamp.
  514. {
  515. V_INAME(IDirectMusicGraph::StampPMsg);
  516. V_BUFPTR_WRITE(pPMsg, sizeof(DMUS_PMSG));
  517. HRESULT hr = S_OK;
  518. if( NULL == pPMsg )
  519. {
  520. return E_INVALIDARG;
  521. }
  522. EnterCriticalSection(&m_CrSec);
  523. CToolRef* pPlace = GetHead();
  524. IDirectMusicTool* pPriorTool;
  525. DWORD dwType;
  526. DWORD dwPChannel;
  527. pPriorTool = pPMsg->pTool;
  528. dwType = pPMsg->dwType;
  529. dwPChannel = pPMsg->dwPChannel;
  530. if( pPriorTool )
  531. {
  532. for( ; pPlace; pPlace = pPlace->GetNext() )
  533. {
  534. if( pPriorTool == pPlace->m_pTool )
  535. {
  536. pPlace = pPlace->GetNext();
  537. break;
  538. }
  539. }
  540. }
  541. BOOL fFound = FALSE;
  542. for( ; pPlace ; pPlace = pPlace->GetNext() )
  543. {
  544. if( CheckType(dwType, pPlace) )
  545. {
  546. if( !pPlace->m_pdwPChannels || (dwPChannel >= DMUS_PCHANNEL_BROADCAST_GROUPS))
  547. {
  548. // supports all tracks, or requested channel is broadcast.
  549. break;
  550. }
  551. DWORD cCount;
  552. // scan through the array of PChannels to see if this one
  553. // supports dwPChannel
  554. for( cCount = 0; cCount < pPlace->m_dwPCArraySize; cCount++)
  555. {
  556. if( dwPChannel == pPlace->m_pdwPChannels[cCount] )
  557. {
  558. fFound = TRUE;
  559. // yep, it supports it
  560. break;
  561. }
  562. }
  563. }
  564. if (fFound) break;
  565. }
  566. // release the current tool
  567. if( pPMsg->pTool )
  568. {
  569. pPMsg->pTool->Release();
  570. pPMsg->pTool = NULL;
  571. }
  572. if( NULL == pPlace )
  573. {
  574. hr = DMUS_S_LAST_TOOL;
  575. }
  576. else
  577. {
  578. // if there is no graph pointer, set it to this
  579. if( NULL == pPMsg->pGraph )
  580. {
  581. pPMsg->pGraph = this;
  582. AddRef();
  583. }
  584. // set to the new tool and addref
  585. if (pPlace->m_pTool) // Just in case, the ptool sometimes goes away in debugging situations after a long break.
  586. {
  587. pPMsg->pTool = pPlace->m_pTool;
  588. pPMsg->pTool->AddRef();
  589. }
  590. // set the event's queue type
  591. pPMsg->dwFlags &= ~(DMUS_PMSGF_TOOL_IMMEDIATE | DMUS_PMSGF_TOOL_QUEUE | DMUS_PMSGF_TOOL_ATTIME);
  592. pPMsg->dwFlags |= pPlace->m_dwQueue;
  593. }
  594. LeaveCriticalSection(&m_CrSec);
  595. return hr;
  596. }
  597. /////////////////////////////////////////////////////////////////////////////
  598. // IPersist
  599. HRESULT CGraph::GetClassID( CLSID* pClassID )
  600. {
  601. V_INAME(CGraph::GetClassID);
  602. V_PTR_WRITE(pClassID, CLSID);
  603. *pClassID = CLSID_DirectMusicGraph;
  604. return S_OK;
  605. }
  606. /////////////////////////////////////////////////////////////////////////////
  607. // IPersistStream functions
  608. HRESULT CGraph::IsDirty()
  609. {
  610. return S_FALSE;
  611. }
  612. HRESULT CGraph::Load( IStream* pIStream )
  613. {
  614. V_INAME(IPersistStream::Load);
  615. V_INTERFACE(pIStream);
  616. CRiffParser Parser(pIStream);
  617. RIFFIO ckMain;
  618. HRESULT hr = S_OK;
  619. Parser.EnterList(&ckMain);
  620. if (Parser.NextChunk(&hr) && (ckMain.fccType == DMUS_FOURCC_TOOLGRAPH_FORM))
  621. {
  622. Shutdown(); // Clear out the tools that are currently in the graph.
  623. hr = Load(&Parser);
  624. }
  625. else
  626. {
  627. Trace(1,"Error: Unknown file format when parsing Tool Graph\n");
  628. hr = DMUS_E_DESCEND_CHUNK_FAIL;
  629. }
  630. return hr;
  631. }
  632. HRESULT CGraph::Load(CRiffParser *pParser)
  633. {
  634. RIFFIO ckNext;
  635. RIFFIO ckChild;
  636. HRESULT hr = S_OK;
  637. pParser->EnterList(&ckNext);
  638. while(pParser->NextChunk(&hr))
  639. {
  640. switch(ckNext.ckid)
  641. {
  642. case DMUS_FOURCC_GUID_CHUNK:
  643. hr = pParser->Read( &m_guidObject, sizeof(GUID) );
  644. m_dwValidData |= DMUS_OBJ_OBJECT;
  645. break;
  646. case DMUS_FOURCC_VERSION_CHUNK:
  647. hr = pParser->Read( &m_vVersion, sizeof(DMUS_VERSION) );
  648. m_dwValidData |= DMUS_OBJ_VERSION;
  649. break;
  650. case DMUS_FOURCC_CATEGORY_CHUNK:
  651. hr = pParser->Read( &m_wszCategory, sizeof(WCHAR)*DMUS_MAX_CATEGORY );
  652. m_wszCategory[DMUS_MAX_CATEGORY-1] = '\0';
  653. m_dwValidData |= DMUS_OBJ_CATEGORY;
  654. break;
  655. case DMUS_FOURCC_DATE_CHUNK:
  656. hr = pParser->Read( &m_ftDate, sizeof(FILETIME) );
  657. m_dwValidData |= DMUS_OBJ_DATE;
  658. break;
  659. case FOURCC_LIST:
  660. switch(ckNext.fccType)
  661. {
  662. case DMUS_FOURCC_UNFO_LIST:
  663. pParser->EnterList(&ckChild);
  664. while (pParser->NextChunk(&hr))
  665. {
  666. if ( ckChild.ckid == DMUS_FOURCC_UNAM_CHUNK)
  667. {
  668. hr = pParser->Read(&m_wszName, sizeof(m_wszName));
  669. m_wszName[DMUS_MAX_NAME-1] = '\0';
  670. m_dwValidData |= DMUS_OBJ_NAME;
  671. }
  672. }
  673. pParser->LeaveList();
  674. break;
  675. case DMUS_FOURCC_TOOL_LIST:
  676. pParser->EnterList(&ckChild);
  677. while(pParser->NextChunk(&hr))
  678. {
  679. if ((ckChild.ckid == FOURCC_RIFF) &&
  680. (ckChild.fccType == DMUS_FOURCC_TOOL_FORM))
  681. {
  682. hr = LoadTool(pParser);
  683. }
  684. }
  685. pParser->LeaveList();
  686. break;
  687. }
  688. break;
  689. }
  690. }
  691. pParser->LeaveList();
  692. return hr;
  693. }
  694. HRESULT CGraph::LoadTool(CRiffParser *pParser)
  695. {
  696. RIFFIO ckNext;
  697. DWORD cbSize;
  698. DMUS_IO_TOOL_HEADER ioDMToolHdr;
  699. DWORD *pdwPChannels = NULL;
  700. HRESULT hr = S_OK;
  701. pParser->EnterList(&ckNext);
  702. if (pParser->NextChunk(&hr))
  703. {
  704. if(ckNext.ckid != DMUS_FOURCC_TOOL_CHUNK)
  705. {
  706. pParser->LeaveList();
  707. Trace(1,"Error: Tool header chunk not first in tool list.\n");
  708. return DMUS_E_TOOL_HDR_NOT_FIRST_CK;
  709. }
  710. hr = pParser->Read(&ioDMToolHdr, sizeof(DMUS_IO_TOOL_HEADER));
  711. if(ioDMToolHdr.ckid == 0 && ioDMToolHdr.fccType == NULL)
  712. {
  713. pParser->LeaveList();
  714. Trace(1,"Error: Invalid Tool header.\n");
  715. return DMUS_E_INVALID_TOOL_HDR;
  716. }
  717. if(ioDMToolHdr.cPChannels)
  718. {
  719. pdwPChannels = new DWORD[ioDMToolHdr.cPChannels];
  720. // subtract 1 from cPChannels, because 1 element is actually stored
  721. // in the ioDMToolHdr array.
  722. cbSize = (ioDMToolHdr.cPChannels - 1) * sizeof(DWORD);
  723. if(pdwPChannels)
  724. {
  725. pdwPChannels[0] = ioDMToolHdr.dwPChannels[0];
  726. if( cbSize )
  727. {
  728. hr = pParser->Read(&pdwPChannels[1], cbSize);
  729. if(FAILED(hr))
  730. {
  731. delete [] pdwPChannels;
  732. pdwPChannels = NULL;
  733. pParser->LeaveList();
  734. Trace(1,"Error: File read error loading Tool.\n");
  735. return DMUS_E_CANNOTREAD;
  736. }
  737. }
  738. }
  739. else
  740. {
  741. hr = E_OUTOFMEMORY;
  742. }
  743. }
  744. }
  745. else
  746. {
  747. pParser->LeaveList();
  748. Trace(1,"Error reading Tool chunk - not RIFF format.\n");
  749. hr = DMUS_E_DESCEND_CHUNK_FAIL;
  750. }
  751. while (pParser->NextChunk(&hr))
  752. {
  753. if((((ckNext.ckid == FOURCC_LIST) || (ckNext.ckid == FOURCC_RIFF))
  754. && ckNext.fccType == ioDMToolHdr.fccType) ||
  755. (ckNext.ckid == ioDMToolHdr.ckid))
  756. {
  757. pParser->SeekBack();
  758. hr = CreateTool(ioDMToolHdr, pParser->GetStream(), pdwPChannels);
  759. pParser->SeekForward();
  760. }
  761. }
  762. pParser->LeaveList();
  763. if( pdwPChannels )
  764. {
  765. delete [] pdwPChannels;
  766. pdwPChannels = NULL;
  767. }
  768. return hr;
  769. }
  770. HRESULT CGraph::CreateTool(DMUS_IO_TOOL_HEADER ioDMToolHdr, IStream *pStream, DWORD *pdwPChannels)
  771. {
  772. assert(pStream);
  773. IDirectMusicTool* pDMTool = NULL;
  774. HRESULT hr = CoCreateInstance(ioDMToolHdr.guidClassID,
  775. NULL,
  776. CLSCTX_INPROC,
  777. IID_IDirectMusicTool,
  778. (void**)&pDMTool);
  779. IPersistStream *pIPersistStream = NULL;
  780. if(SUCCEEDED(hr))
  781. {
  782. hr = pDMTool->QueryInterface(IID_IPersistStream, (void **)&pIPersistStream);
  783. }
  784. else
  785. {
  786. Trace(1,"Error creating tool for loading\n");
  787. }
  788. if(SUCCEEDED(hr))
  789. {
  790. hr = pIPersistStream->Load(pStream);
  791. if (FAILED(hr))
  792. {
  793. Trace(1,"Error loading data into tool\n");
  794. }
  795. }
  796. if(SUCCEEDED(hr))
  797. {
  798. hr = InsertTool(pDMTool, pdwPChannels, ioDMToolHdr.cPChannels, ioDMToolHdr.lIndex, &ioDMToolHdr.guidClassID);
  799. }
  800. if(pIPersistStream)
  801. {
  802. pIPersistStream->Release();
  803. }
  804. if(pDMTool)
  805. {
  806. pDMTool->Release();
  807. }
  808. return hr;
  809. }
  810. HRESULT CGraph::Save( IStream* pIStream, BOOL fClearDirty )
  811. {
  812. return E_NOTIMPL;
  813. }
  814. HRESULT CGraph::GetSizeMax( ULARGE_INTEGER FAR* pcbSize )
  815. {
  816. return E_NOTIMPL;
  817. }
  818. /////////////////////////////////////////////////////////////////////////////
  819. // IDirectMusicObject
  820. STDMETHODIMP CGraph::GetDescriptor(LPDMUS_OBJECTDESC pDesc)
  821. {
  822. // Argument validation
  823. V_INAME(CGraph::GetDescriptor);
  824. V_STRUCTPTR_WRITE(pDesc, DMUS_OBJECTDESC);
  825. memset( pDesc, 0, sizeof(DMUS_OBJECTDESC));
  826. pDesc->dwSize = sizeof(DMUS_OBJECTDESC);
  827. pDesc->guidClass = CLSID_DirectMusicGraph;
  828. pDesc->guidObject = m_guidObject;
  829. pDesc->ftDate = m_ftDate;
  830. pDesc->vVersion = m_vVersion;
  831. StringCchCopyW( pDesc->wszName, DMUS_MAX_NAME, m_wszName);
  832. StringCchCopyW( pDesc->wszCategory, DMUS_MAX_CATEGORY, m_wszCategory);
  833. StringCchCopyW( pDesc->wszFileName, DMUS_MAX_FILENAME, m_wszFileName);
  834. pDesc->dwValidData = ( m_dwValidData | DMUS_OBJ_CLASS );
  835. return S_OK;
  836. }
  837. STDMETHODIMP CGraph::SetDescriptor(LPDMUS_OBJECTDESC pDesc)
  838. {
  839. // Argument validation
  840. V_INAME(CGraph::SetDescriptor);
  841. V_STRUCTPTR_READ(pDesc, DMUS_OBJECTDESC);
  842. HRESULT hr = E_INVALIDARG;
  843. DWORD dw = 0;
  844. if( pDesc->dwSize >= sizeof(DMUS_OBJECTDESC) )
  845. {
  846. if( pDesc->dwValidData & DMUS_OBJ_OBJECT )
  847. {
  848. m_guidObject = pDesc->guidObject;
  849. dw |= DMUS_OBJ_OBJECT;
  850. }
  851. if( pDesc->dwValidData & DMUS_OBJ_NAME )
  852. {
  853. StringCchCopyW(m_wszName, DMUS_MAX_NAME, pDesc->wszName);
  854. dw |= DMUS_OBJ_NAME;
  855. }
  856. if( pDesc->dwValidData & DMUS_OBJ_CATEGORY )
  857. {
  858. StringCchCopyW(m_wszCategory, DMUS_MAX_CATEGORY, pDesc->wszCategory);
  859. dw |= DMUS_OBJ_CATEGORY;
  860. }
  861. if( ( pDesc->dwValidData & DMUS_OBJ_FILENAME ) ||
  862. ( pDesc->dwValidData & DMUS_OBJ_FULLPATH ) )
  863. {
  864. StringCchCopyW(m_wszFileName, DMUS_MAX_FILENAME, pDesc->wszFileName);
  865. dw |= (pDesc->dwValidData & (DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH));
  866. }
  867. if( pDesc->dwValidData & DMUS_OBJ_VERSION )
  868. {
  869. m_vVersion = pDesc->vVersion;
  870. dw |= DMUS_OBJ_VERSION;
  871. }
  872. if( pDesc->dwValidData & DMUS_OBJ_DATE )
  873. {
  874. m_ftDate = pDesc->ftDate;
  875. dw |= DMUS_OBJ_DATE;
  876. }
  877. m_dwValidData |= dw;
  878. if( pDesc->dwValidData & (~dw) )
  879. {
  880. Trace(2,"Warning: ToolGraph::SetDescriptor was not able to handle all passed fields, dwValidData bits %lx.\n",pDesc->dwValidData & (~dw));
  881. hr = S_FALSE; // there were extra fields we didn't parse;
  882. pDesc->dwValidData = dw;
  883. }
  884. else
  885. {
  886. hr = S_OK;
  887. }
  888. }
  889. else
  890. {
  891. Trace(1,"Error: Size of descriptor too large for Tool Graph to parse.\n");
  892. }
  893. return hr;
  894. }
  895. STDMETHODIMP CGraph::ParseDescriptor(LPSTREAM pIStream, LPDMUS_OBJECTDESC pDesc)
  896. {
  897. V_INAME(CGraph::ParseDescriptor);
  898. V_INTERFACE(pIStream);
  899. V_STRUCTPTR_WRITE(pDesc, DMUS_OBJECTDESC);
  900. CRiffParser Parser(pIStream);
  901. RIFFIO ckMain;
  902. RIFFIO ckNext;
  903. RIFFIO ckUNFO;
  904. HRESULT hr = S_OK;
  905. DWORD dwValidData;
  906. Parser.EnterList(&ckMain);
  907. if (Parser.NextChunk(&hr) && (ckMain.fccType == DMUS_FOURCC_TOOLGRAPH_FORM))
  908. {
  909. dwValidData = DMUS_OBJ_CLASS;
  910. pDesc->guidClass = CLSID_DirectMusicGraph;
  911. Parser.EnterList(&ckNext);
  912. while(Parser.NextChunk(&hr))
  913. {
  914. switch(ckNext.ckid)
  915. {
  916. case DMUS_FOURCC_GUID_CHUNK:
  917. hr = Parser.Read( &pDesc->guidObject, sizeof(GUID) );
  918. dwValidData |= DMUS_OBJ_OBJECT;
  919. break;
  920. case DMUS_FOURCC_VERSION_CHUNK:
  921. hr = Parser.Read( &pDesc->vVersion, sizeof(DMUS_VERSION) );
  922. dwValidData |= DMUS_OBJ_VERSION;
  923. break;
  924. case DMUS_FOURCC_CATEGORY_CHUNK:
  925. hr = Parser.Read( &pDesc->wszCategory, sizeof(pDesc->wszCategory) );
  926. pDesc->wszCategory[DMUS_MAX_CATEGORY-1] = '\0';
  927. dwValidData |= DMUS_OBJ_CATEGORY;
  928. break;
  929. case DMUS_FOURCC_DATE_CHUNK:
  930. hr = Parser.Read( &pDesc->ftDate, sizeof(FILETIME) );
  931. dwValidData |= DMUS_OBJ_DATE;
  932. break;
  933. case FOURCC_LIST:
  934. switch(ckNext.fccType)
  935. {
  936. case DMUS_FOURCC_UNFO_LIST:
  937. Parser.EnterList(&ckUNFO);
  938. while (Parser.NextChunk(&hr))
  939. {
  940. if (ckUNFO.ckid == DMUS_FOURCC_UNAM_CHUNK)
  941. {
  942. hr = Parser.Read(&pDesc->wszName, sizeof(pDesc->wszName));
  943. pDesc->wszName[DMUS_MAX_NAME-1] = '\0';
  944. dwValidData |= DMUS_OBJ_NAME;
  945. }
  946. }
  947. Parser.LeaveList();
  948. break;
  949. }
  950. break;
  951. }
  952. }
  953. Parser.LeaveList();
  954. }
  955. else
  956. {
  957. Trace(1,"Error: Parsing Tool Graph - invalid file format\n");
  958. hr = DMUS_E_CHUNKNOTFOUND;
  959. }
  960. if (SUCCEEDED(hr))
  961. {
  962. pDesc->dwValidData = dwValidData;
  963. }
  964. return hr;
  965. }
  966. void CGraphList::Clear()
  967. {
  968. CGraph *pGraph;
  969. while (pGraph = RemoveHead())
  970. {
  971. pGraph->Release();
  972. }
  973. }