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.

759 lines
19 KiB

  1. //
  2. // dmstrm.cpp
  3. //
  4. // Copyright (c) 1995-2000 Microsoft Corporation
  5. //
  6. #include "debug.h"
  7. #include "dmusicc.h"
  8. #include "..\shared\dmstrm.h"
  9. #include "..\shared\validate.h"
  10. /////////////////////////////////////////////////////////////////////////////
  11. // AllocDIrectMusicStream
  12. STDAPI AllocDirectMusicStream(IStream* pIStream, IDMStream** ppIDMStream)
  13. {
  14. if(pIStream == NULL || ppIDMStream == NULL)
  15. {
  16. return E_INVALIDARG;
  17. }
  18. if((*ppIDMStream = (IDMStream*) new CDirectMusicStream()) == NULL)
  19. {
  20. return E_OUTOFMEMORY;
  21. }
  22. ((CDirectMusicStream*)*ppIDMStream)->Init(pIStream);
  23. return S_OK;
  24. }
  25. //////////////////////////////////////////////////////////////////////
  26. // CDirectMusicStream::CDirectMusicStream
  27. CDirectMusicStream::CDirectMusicStream() :
  28. m_cRef(1),
  29. m_pStream(NULL)
  30. {
  31. }
  32. //////////////////////////////////////////////////////////////////////
  33. // CDirectMusicStream::~CDirectMusicStream
  34. CDirectMusicStream::~CDirectMusicStream()
  35. {
  36. if(m_pStream != NULL)
  37. {
  38. m_pStream->Release();
  39. }
  40. }
  41. //////////////////////////////////////////////////////////////////////
  42. // CDirectMusicStream::Init
  43. STDMETHODIMP CDirectMusicStream::Init(IStream* pStream)
  44. {
  45. SetStream(pStream);
  46. return S_OK;
  47. }
  48. //////////////////////////////////////////////////////////////////////
  49. // IUnknown
  50. //////////////////////////////////////////////////////////////////////
  51. // CDirectMusicStream::QueryInterface
  52. STDMETHODIMP CDirectMusicStream::QueryInterface(const IID &iid, void **ppv)
  53. {
  54. V_INAME(CDirectMusicStream::QueryInterface);
  55. V_PTRPTR_WRITE(ppv);
  56. V_REFGUID(iid);
  57. if(iid == IID_IUnknown || iid == IID_IDMStream)
  58. {
  59. *ppv = static_cast<IDMStream*>(this);
  60. }
  61. else
  62. {
  63. *ppv = NULL;
  64. return E_NOINTERFACE;
  65. }
  66. reinterpret_cast<IUnknown*>(this)->AddRef();
  67. return S_OK;
  68. }
  69. //////////////////////////////////////////////////////////////////////
  70. // CDirectMusicStream::AddRef
  71. STDMETHODIMP_(ULONG) CDirectMusicStream::AddRef()
  72. {
  73. return InterlockedIncrement(&m_cRef);
  74. }
  75. //////////////////////////////////////////////////////////////////////
  76. // CDirectMusicStream::Release
  77. STDMETHODIMP_(ULONG) CDirectMusicStream::Release()
  78. {
  79. if(!InterlockedDecrement(&m_cRef))
  80. {
  81. delete this;
  82. return 0;
  83. }
  84. return m_cRef;
  85. }
  86. //////////////////////////////////////////////////////////////////////
  87. // CDirectMusicStream::SetStream
  88. STDMETHODIMP CDirectMusicStream::SetStream(IStream* pStream)
  89. {
  90. if(m_pStream != NULL)
  91. {
  92. m_pStream->Release();
  93. }
  94. m_pStream = pStream;
  95. if(m_pStream != NULL)
  96. {
  97. m_pStream->AddRef();
  98. }
  99. return S_OK;
  100. }
  101. //////////////////////////////////////////////////////////////////////
  102. // CDirectMusicStream::GetStream
  103. STDMETHODIMP_(IStream*) CDirectMusicStream::GetStream()
  104. {
  105. if(m_pStream != NULL)
  106. {
  107. m_pStream->AddRef();
  108. }
  109. return m_pStream;
  110. }
  111. //////////////////////////////////////////////////////////////////////
  112. // IDMStream
  113. //////////////////////////////////////////////////////////////////////
  114. // CDirectMusicStream::Descend
  115. STDMETHODIMP CDirectMusicStream::Descend(LPMMCKINFO lpck, LPMMCKINFO lpckParent, UINT wFlags)
  116. {
  117. assert(lpck);
  118. FOURCC ckidFind; // Chunk ID to find (or NULL)
  119. FOURCC fccTypeFind; // Form/list type to find (or NULL)
  120. // Figure out what chunk id and form/list type for which to search
  121. if(wFlags & MMIO_FINDCHUNK)
  122. {
  123. ckidFind = lpck->ckid;
  124. fccTypeFind = NULL;
  125. }
  126. else if(wFlags & MMIO_FINDRIFF)
  127. {
  128. ckidFind = FOURCC_RIFF;
  129. fccTypeFind = lpck->fccType;
  130. }
  131. else if(wFlags & MMIO_FINDLIST)
  132. {
  133. ckidFind = FOURCC_LIST;
  134. fccTypeFind = lpck->fccType;
  135. }
  136. else
  137. {
  138. ckidFind = fccTypeFind = NULL;
  139. }
  140. lpck->dwFlags = 0L;
  141. for(;;)
  142. {
  143. HRESULT hr;
  144. LARGE_INTEGER li;
  145. ULARGE_INTEGER uli;
  146. ULONG cbRead;
  147. // Read the chunk header
  148. hr = m_pStream->Read(lpck, 2 * sizeof(DWORD), &cbRead);
  149. if (FAILED(hr) || (cbRead != 2 * sizeof(DWORD)))
  150. {
  151. Trace(1,"Error: Unable to read file.\n");
  152. return DMUS_E_DESCEND_CHUNK_FAIL;
  153. }
  154. // Store the offset of the data part of the chunk
  155. li.QuadPart = 0;
  156. hr = m_pStream->Seek(li, STREAM_SEEK_CUR, &uli);
  157. if(FAILED(hr))
  158. {
  159. Trace(1,"Error: Unable to read file.\n");
  160. return DMUS_E_CANNOTSEEK;
  161. }
  162. else
  163. {
  164. lpck->dwDataOffset = uli.LowPart;
  165. }
  166. // See if the chunk is within the parent chunk (if given)
  167. if((lpckParent != NULL) &&
  168. (lpck->dwDataOffset - 8L >=
  169. lpckParent->dwDataOffset + lpckParent->cksize))
  170. {
  171. Trace(1,"Error: Unable to read file.\n");
  172. return DMUS_E_DESCEND_CHUNK_FAIL;
  173. }
  174. // If the chunk is a 'RIFF' or 'LIST' chunk, read the
  175. // form type or list type
  176. if((lpck->ckid == FOURCC_RIFF) || (lpck->ckid == FOURCC_LIST))
  177. {
  178. ULONG cbRead;
  179. hr = m_pStream->Read(&lpck->fccType, sizeof(DWORD), &cbRead);
  180. if(FAILED(hr) || (cbRead != sizeof(DWORD)))
  181. {
  182. Trace(1,"Error: Unable to read file.\n");
  183. return DMUS_E_DESCEND_CHUNK_FAIL;
  184. }
  185. }
  186. else
  187. {
  188. lpck->fccType = NULL;
  189. }
  190. // If this is the chunk we're looking for, stop looking
  191. if(((ckidFind == NULL) || (ckidFind == lpck->ckid)) &&
  192. ((fccTypeFind == NULL) || (fccTypeFind == lpck->fccType)))
  193. {
  194. break;
  195. }
  196. // Ascend out of the chunk and try again
  197. HRESULT w = Ascend(lpck, 0);
  198. if(FAILED(w))
  199. {
  200. return w;
  201. }
  202. }
  203. return S_OK;
  204. }
  205. //////////////////////////////////////////////////////////////////////
  206. // CDirectMusicStream::Ascend
  207. STDMETHODIMP CDirectMusicStream::Ascend(LPMMCKINFO lpck, UINT /*wFlags*/)
  208. {
  209. assert(lpck);
  210. HRESULT hr;
  211. LARGE_INTEGER li;
  212. ULARGE_INTEGER uli;
  213. if (lpck->dwFlags & MMIO_DIRTY)
  214. {
  215. // <lpck> refers to a chunk created by CreateChunk();
  216. // check that the chunk size that was written when
  217. // CreateChunk() was called is the real chunk size;
  218. // if not, fix it
  219. LONG lOffset; // current offset in file
  220. LONG lActualSize; // actual size of chunk data
  221. li.QuadPart = 0;
  222. hr = m_pStream->Seek(li, STREAM_SEEK_CUR, &uli);
  223. if(FAILED(hr))
  224. {
  225. Trace(1,"Error: Unable to write file.\n");
  226. return DMUS_E_CANNOTSEEK;
  227. }
  228. else
  229. {
  230. lOffset = uli.LowPart;
  231. }
  232. if((lActualSize = lOffset - lpck->dwDataOffset) < 0)
  233. {
  234. Trace(1,"Error: Unable to write file.\n");
  235. return DMUS_E_CANNOTWRITE;
  236. }
  237. if(LOWORD(lActualSize) & 1)
  238. {
  239. ULONG cbWritten;
  240. // Chunk size is odd -- write a null pad byte
  241. hr = m_pStream->Write("\0", 1, &cbWritten);
  242. if(FAILED(hr) || cbWritten != 1)
  243. {
  244. Trace(1,"Error: Unable to write file.\n");
  245. return DMUS_E_CANNOTWRITE;
  246. }
  247. }
  248. if(lpck->cksize == (DWORD)lActualSize)
  249. {
  250. return S_OK;
  251. }
  252. // Fix the chunk header
  253. lpck->cksize = lActualSize;
  254. li.QuadPart = lpck->dwDataOffset - sizeof(DWORD);
  255. hr = m_pStream->Seek(li, STREAM_SEEK_SET, &uli);
  256. if(FAILED(hr))
  257. {
  258. Trace(1,"Error: Unable to write file.\n");
  259. return DMUS_E_CANNOTSEEK;
  260. }
  261. ULONG cbWritten;
  262. hr = m_pStream->Write(&lpck->cksize, sizeof(DWORD), &cbWritten);
  263. if(FAILED(hr) || cbWritten != sizeof(DWORD))
  264. {
  265. Trace(1,"Error: Unable to write file.\n");
  266. return DMUS_E_CANNOTWRITE;
  267. }
  268. }
  269. // Seek to the end of the chunk, past the null pad byte
  270. // (which is only there if chunk size is odd)
  271. li.QuadPart = lpck->dwDataOffset + lpck->cksize + (lpck->cksize & 1L);
  272. hr = m_pStream->Seek(li, STREAM_SEEK_SET, &uli);
  273. if(FAILED(hr))
  274. {
  275. Trace(1,"Error: Unable to write file.\n");
  276. return DMUS_E_CANNOTSEEK;
  277. }
  278. return S_OK;
  279. }
  280. //////////////////////////////////////////////////////////////////////
  281. // CDirectMusicStream::CreateChunk
  282. STDMETHODIMP CDirectMusicStream::CreateChunk(LPMMCKINFO lpck, UINT wFlags)
  283. {
  284. assert(lpck);
  285. UINT iBytes; // Bytes to write
  286. LONG lOffset; // Current offset in file
  287. // Store the offset of the data part of the chunk
  288. LARGE_INTEGER li;
  289. ULARGE_INTEGER uli;
  290. li.QuadPart = 0;
  291. HRESULT hr = m_pStream->Seek(li, STREAM_SEEK_CUR, &uli);
  292. if(FAILED(hr))
  293. {
  294. Trace(1,"Error: Unable to write file.\n");
  295. return DMUS_E_CANNOTSEEK;
  296. }
  297. else
  298. {
  299. lOffset = uli.LowPart;
  300. }
  301. lpck->dwDataOffset = lOffset + 2 * sizeof(DWORD);
  302. // figure out if a form/list type needs to be written
  303. if(wFlags & MMIO_CREATERIFF)
  304. {
  305. lpck->ckid = FOURCC_RIFF, iBytes = 3 * sizeof(DWORD);
  306. }
  307. else if(wFlags & MMIO_CREATELIST)
  308. {
  309. lpck->ckid = FOURCC_LIST, iBytes = 3 * sizeof(DWORD);
  310. }
  311. else
  312. {
  313. iBytes = 2 * sizeof(DWORD);
  314. }
  315. // Write the chunk header
  316. ULONG cbWritten;
  317. hr = m_pStream->Write(lpck, iBytes, &cbWritten);
  318. if(FAILED(hr) || cbWritten != iBytes)
  319. {
  320. Trace(1,"Error: Unable to write file.\n");
  321. return DMUS_E_CANNOTWRITE;
  322. }
  323. lpck->dwFlags = MMIO_DIRTY;
  324. return S_OK;
  325. }
  326. CRiffParser::CRiffParser(IStream *pStream)
  327. {
  328. assert(pStream);
  329. m_fDebugOn = FALSE;
  330. m_pStream = pStream;
  331. m_pParent = NULL;
  332. m_pChunk = NULL;
  333. m_lRead = 0;
  334. m_fFirstPass = TRUE;
  335. m_fComponentFailed = FALSE;
  336. m_fInComponent = FALSE;
  337. }
  338. void CRiffParser::EnterList(RIFFIO *pChunk)
  339. {
  340. assert (pChunk);
  341. pChunk->lRead = 0;
  342. pChunk->pParent = m_pChunk; // Previous chunk (could be NULL.)
  343. m_pParent = m_pChunk;
  344. m_pChunk = pChunk;
  345. m_fFirstPass = TRUE;
  346. }
  347. void CRiffParser::LeaveList()
  348. {
  349. assert (m_pChunk);
  350. if (m_pChunk)
  351. {
  352. m_pChunk = m_pChunk->pParent;
  353. if (m_pChunk)
  354. {
  355. m_pParent = m_pChunk->pParent;
  356. }
  357. }
  358. }
  359. BOOL CRiffParser::NextChunk(HRESULT * pHr)
  360. {
  361. BOOL fMore = FALSE;
  362. if (SUCCEEDED(*pHr))
  363. {
  364. // If this is the first time we've entered this list, there is no previous chunk.
  365. if (m_fFirstPass)
  366. {
  367. // Clear the flag.
  368. m_fFirstPass = FALSE;
  369. }
  370. else
  371. {
  372. // Clean up the previous pass.
  373. *pHr = LeaveChunk();
  374. }
  375. // Find out if there are more chunks to read.
  376. fMore = MoreChunks();
  377. // If so, and we don't have any failure, go ahead and read the next chunk header.
  378. if (fMore && SUCCEEDED(*pHr))
  379. {
  380. *pHr = EnterChunk();
  381. }
  382. }
  383. else
  384. {
  385. #ifdef DBG
  386. char szName[5];
  387. if (m_fDebugOn)
  388. {
  389. szName[4] = 0;
  390. strncpy(szName,(char *)&m_pChunk->ckid,4);
  391. Trace(0,"Error parsing %s, Read %ld of %ld\n",szName,m_pChunk->lRead,RIFF_ALIGN(m_pChunk->cksize));
  392. }
  393. #endif
  394. // If we were in a component, it's okay to fail. Mark that fact by setting
  395. // m_fComponentFailed then properly pull out of the chunk so we can
  396. // continue reading.
  397. if (m_fInComponent)
  398. {
  399. m_fComponentFailed = TRUE;
  400. // We don't need to check for first pass, because we must have gotten
  401. // that far. Instead, we just clean up from the failed chunk.
  402. // Note that this sets the hresult to S_OK, which is what we want.
  403. // Later, the caller needs to call ComponentFailed() to find out if
  404. // this error occured.
  405. *pHr = LeaveChunk();
  406. }
  407. else
  408. {
  409. // Clean up but leave the error code.
  410. LeaveChunk();
  411. }
  412. }
  413. return fMore && SUCCEEDED(*pHr);
  414. }
  415. BOOL CRiffParser::MoreChunks()
  416. {
  417. assert(m_pChunk);
  418. if (m_pChunk)
  419. {
  420. if (m_pParent)
  421. {
  422. // Return TRUE if there's enough room for another chunk.
  423. return (m_pParent->lRead < (m_pParent->cksize - 8));
  424. }
  425. else
  426. {
  427. // This must be a top level chunk, in which case there would only be one to read.
  428. return (m_pChunk->lRead == 0);
  429. }
  430. }
  431. // This should never happen unless CRiffParser is used incorrectly, in which
  432. // case the assert will help debug. But, in the interest of making Prefix happy...
  433. return false;
  434. }
  435. HRESULT CRiffParser::EnterChunk()
  436. {
  437. assert(m_pChunk);
  438. if (m_pChunk)
  439. {
  440. // Read the chunk header
  441. HRESULT hr = m_pStream->Read(m_pChunk, 2 * sizeof(DWORD), NULL);
  442. if (SUCCEEDED(hr))
  443. {
  444. #ifdef DBG
  445. char szName[5];
  446. if (m_fDebugOn)
  447. {
  448. szName[4] = 0;
  449. strncpy(szName,(char *)&m_pChunk->ckid,4);
  450. ULARGE_INTEGER ul;
  451. LARGE_INTEGER li;
  452. li.QuadPart = 0;
  453. HRESULT hr = m_pStream->Seek(li, STREAM_SEEK_CUR, &ul);
  454. Trace(0,"Entering %s, Length %ld, File position is %ld",szName,m_pChunk->cksize,(long)ul.QuadPart);
  455. }
  456. #endif
  457. // Clear bytes read field.
  458. m_pChunk->lRead = 0;
  459. // Check to see if this is a container (LIST or RIFF.)
  460. if((m_pChunk->ckid == FOURCC_RIFF) || (m_pChunk->ckid == FOURCC_LIST))
  461. {
  462. hr = m_pStream->Read(&m_pChunk->fccType, sizeof(DWORD), NULL);
  463. if (SUCCEEDED(hr))
  464. {
  465. m_pChunk->lRead += sizeof(DWORD);
  466. #ifdef DBG
  467. if (m_fDebugOn)
  468. {
  469. strncpy(szName,(char *)&m_pChunk->fccType,4);
  470. Trace(0," Type %s",szName);
  471. }
  472. #endif
  473. }
  474. else
  475. {
  476. Trace(1,"Error: Unable to read file.\n");
  477. }
  478. }
  479. #ifdef DBG
  480. if (m_fDebugOn) Trace(0,"\n");
  481. #endif
  482. }
  483. else
  484. {
  485. Trace(1,"Error: Unable to read file.\n");
  486. }
  487. return hr;
  488. }
  489. // This should never happen unless CRiffParser is used incorrectly, in which
  490. // case the assert will help debug. But, in the interest of making Prefix happy...
  491. return E_FAIL;
  492. }
  493. HRESULT CRiffParser::LeaveChunk()
  494. {
  495. HRESULT hr = S_OK;
  496. assert(m_pChunk);
  497. if (m_pChunk)
  498. {
  499. m_fInComponent = false;
  500. // Get the rounded up size of the chunk.
  501. long lSize = RIFF_ALIGN(m_pChunk->cksize);
  502. // Increment the parent's count of bytes read so far.
  503. if (m_pParent)
  504. {
  505. m_pParent->lRead += lSize + (2 * sizeof(DWORD));
  506. if (m_pParent->lRead > RIFF_ALIGN(m_pParent->cksize))
  507. {
  508. Trace(1,"Error: Unable to read file.\n");
  509. hr = DMUS_E_DESCEND_CHUNK_FAIL; // Goofy error name, but need to be consistent with previous versions.
  510. }
  511. }
  512. #ifdef DBG
  513. char szName[5];
  514. if (m_fDebugOn)
  515. {
  516. szName[4] = 0;
  517. strncpy(szName,(char *)&m_pChunk->ckid,4);
  518. ULARGE_INTEGER ul;
  519. LARGE_INTEGER li;
  520. li.QuadPart = 0;
  521. HRESULT hr = m_pStream->Seek(li, STREAM_SEEK_CUR, &ul);
  522. Trace(0,"Leaving %s, Read %ld of %ld, File Position is %ld\n",szName,m_pChunk->lRead,lSize,(long)ul.QuadPart);
  523. }
  524. #endif
  525. // If we haven't actually read this entire chunk, seek to the end of it.
  526. if (m_pChunk->lRead < lSize)
  527. {
  528. LARGE_INTEGER li;
  529. li.QuadPart = lSize - m_pChunk->lRead;
  530. hr = m_pStream->Seek(li,STREAM_SEEK_CUR,NULL);
  531. // There's a chance it could fail because we are at the end of file with an odd length chunk.
  532. if (FAILED(hr))
  533. {
  534. // If there's a parent, see if this is the last chunk.
  535. if (m_pParent)
  536. {
  537. if (m_pParent->cksize >= (m_pParent->lRead - 1))
  538. {
  539. hr = S_OK;
  540. }
  541. }
  542. // Else, see if we are an odd length.
  543. else if (m_pChunk->cksize & 1)
  544. {
  545. hr = S_OK;
  546. }
  547. }
  548. }
  549. return hr;
  550. }
  551. // This should never happen unless CRiffParser is used incorrectly, in which
  552. // case the assert will help debug. But, in the interest of making Prefix happy...
  553. return E_FAIL;
  554. }
  555. HRESULT CRiffParser::Read(void *pv,ULONG cb)
  556. {
  557. assert(m_pChunk);
  558. if (m_pChunk)
  559. {
  560. // Make sure we don't read beyond the end of the chunk.
  561. if (((long)cb + m_pChunk->lRead) > m_pChunk->cksize)
  562. {
  563. cb -= (cb - (m_pChunk->cksize - m_pChunk->lRead));
  564. }
  565. HRESULT hr = m_pStream->Read(pv,cb,NULL);
  566. if (SUCCEEDED(hr))
  567. {
  568. m_pChunk->lRead += cb;
  569. }
  570. else
  571. {
  572. Trace(1,"Error: Unable to read %ld bytes from file.\n",cb);
  573. }
  574. return hr;
  575. }
  576. // This should never happen unless CRiffParser is used incorrectly, in which
  577. // case the assert will help debug. But, in the interest of making Prefix happy...
  578. return E_FAIL;
  579. }
  580. HRESULT CRiffParser::Skip(ULONG ulBytes)
  581. {
  582. assert(m_pChunk);
  583. if (m_pChunk)
  584. {
  585. // Make sure we don't scan beyond the end of the chunk.
  586. if (((long)ulBytes + m_pChunk->lRead) > m_pChunk->cksize)
  587. {
  588. ulBytes -= (ulBytes - (m_pChunk->cksize - m_pChunk->lRead));
  589. }
  590. LARGE_INTEGER li;
  591. li.HighPart = 0;
  592. li.LowPart = ulBytes;
  593. HRESULT hr = m_pStream->Seek( li, STREAM_SEEK_CUR, NULL );
  594. if (SUCCEEDED(hr))
  595. {
  596. m_pChunk->lRead += ulBytes;
  597. }
  598. return hr;
  599. }
  600. // This should never happen unless CRiffParser is used incorrectly, in which
  601. // case the assert will help debug. But, in the interest of making Prefix happy...
  602. return E_FAIL;
  603. }
  604. void CRiffParser::MarkPosition()
  605. {
  606. assert(m_pChunk);
  607. if (m_pChunk)
  608. {
  609. LARGE_INTEGER li;
  610. ULARGE_INTEGER ul;
  611. li.HighPart = 0;
  612. li.LowPart = 0;
  613. m_pStream->Seek(li, STREAM_SEEK_CUR, &ul);
  614. m_pChunk->liPosition.QuadPart = (LONGLONG) ul.QuadPart;
  615. }
  616. }
  617. HRESULT CRiffParser::SeekBack()
  618. {
  619. assert(m_pChunk);
  620. if (m_pChunk)
  621. {
  622. // Move back to the start of the current chunk. Also, store the
  623. // absolute position because that will be useful later when we need to seek to the
  624. // end of this chunk.
  625. ULARGE_INTEGER ul;
  626. LARGE_INTEGER li;
  627. li.QuadPart = 0;
  628. li.QuadPart -= (m_pChunk->lRead + (2 * sizeof(DWORD)));
  629. HRESULT hr = m_pStream->Seek(li, STREAM_SEEK_CUR, &ul);
  630. // Now, save the absolute position for the end of this chunk.
  631. m_pChunk->liPosition.QuadPart = ul.QuadPart +
  632. RIFF_ALIGN(m_pChunk->cksize) + (2 * sizeof(DWORD));
  633. m_pChunk->lRead = 0;
  634. return hr;
  635. }
  636. return E_FAIL;
  637. }
  638. HRESULT CRiffParser::SeekForward()
  639. {
  640. assert(m_pChunk);
  641. if (m_pChunk)
  642. {
  643. m_pChunk->lRead = RIFF_ALIGN(m_pChunk->cksize);
  644. return m_pStream->Seek(m_pChunk->liPosition, STREAM_SEEK_SET, NULL);
  645. }
  646. return E_FAIL;
  647. }