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.

1211 lines
28 KiB

  1. // stream.cpp
  2. // Copyright (c) 1997-2001 Microsoft Corporation
  3. //
  4. // @doc EXTERNAL
  5. #include <objbase.h>
  6. #include "debug.h"
  7. #include "debug.h"
  8. #include "dmusicc.h" // Using specific path for now, since the headers are changing.
  9. #include "dmusici.h" // Using specific path for now, since the headers are changing.
  10. #include "loader.h"
  11. #include <initguid.h>
  12. #include "riff.h"
  13. #ifndef UNDER_CE
  14. #include <regstr.h>
  15. #include <share.h>
  16. extern BOOL g_fIsUnicode;
  17. CFileStream::CFileStream( CLoader *pLoader)
  18. {
  19. assert(pLoader);
  20. m_cRef = 1;
  21. m_pFile = NULL;
  22. m_pLoader = pLoader;
  23. if (pLoader)
  24. {
  25. pLoader->AddRefP();
  26. }
  27. }
  28. CFileStream::~CFileStream()
  29. {
  30. if (m_pLoader)
  31. {
  32. m_pLoader->ReleaseP();
  33. }
  34. Close();
  35. }
  36. HRESULT CFileStream::Open(WCHAR * lpFileName,DWORD dwDesiredAccess)
  37. {
  38. Close();
  39. wcscpy(m_wszFileName,lpFileName);
  40. assert(dwDesiredAccess == GENERIC_READ || dwDesiredAccess == GENERIC_WRITE);
  41. if( dwDesiredAccess == GENERIC_READ )
  42. {
  43. if (g_fIsUnicode)
  44. {
  45. m_pFile = _wfsopen( lpFileName, L"rb", _SH_DENYWR );
  46. }
  47. else
  48. {
  49. char path[MAX_PATH];
  50. wcstombs( path, lpFileName, MAX_PATH );
  51. m_pFile = _fsopen( path, "rb", _SH_DENYWR );
  52. }
  53. }
  54. else if( dwDesiredAccess == GENERIC_WRITE )
  55. {
  56. if (g_fIsUnicode)
  57. {
  58. m_pFile = _wfsopen( lpFileName, L"wb", _SH_DENYNO );
  59. }
  60. else
  61. {
  62. char path[MAX_PATH];
  63. wcstombs( path, lpFileName, MAX_PATH );
  64. m_pFile = _fsopen( path, "wb", _SH_DENYNO );
  65. }
  66. }
  67. if (m_pFile == NULL)
  68. {
  69. Trace(1, "Warning: The file %S couldn't be opened: %s. Try another path.\n", lpFileName, _strerror(NULL));
  70. return DMUS_E_LOADER_FAILEDOPEN;
  71. }
  72. return S_OK;
  73. }
  74. HRESULT CFileStream::Close()
  75. {
  76. if (m_pFile)
  77. {
  78. fclose(m_pFile);
  79. }
  80. m_pFile = NULL;
  81. return S_OK;
  82. }
  83. STDMETHODIMP CFileStream::QueryInterface( const IID &riid, void **ppvObj )
  84. {
  85. if (riid == IID_IUnknown || riid == IID_IStream) {
  86. *ppvObj = static_cast<IStream*>(this);
  87. AddRef();
  88. return S_OK;
  89. }
  90. else if (riid == IID_IDirectMusicGetLoader)
  91. {
  92. *ppvObj = static_cast<IDirectMusicGetLoader*>(this);
  93. AddRef();
  94. return S_OK;
  95. }
  96. *ppvObj = NULL;
  97. return E_NOINTERFACE;
  98. }
  99. STDMETHODIMP CFileStream::GetLoader(
  100. IDirectMusicLoader ** ppLoader) // @parm Returns an AddRef'd pointer to the loader.
  101. {
  102. if (m_pLoader)
  103. {
  104. return m_pLoader->QueryInterface( IID_IDirectMusicLoader,(void **) ppLoader );
  105. }
  106. assert(false);
  107. *ppLoader = NULL;
  108. return E_NOINTERFACE;
  109. }
  110. STDMETHODIMP_(ULONG) CFileStream::AddRef()
  111. {
  112. return InterlockedIncrement(&m_cRef);
  113. }
  114. STDMETHODIMP_(ULONG) CFileStream::Release()
  115. {
  116. if (!InterlockedDecrement(&m_cRef))
  117. {
  118. delete this;
  119. return 0;
  120. }
  121. return m_cRef;
  122. }
  123. /* IStream methods */
  124. STDMETHODIMP CFileStream::Read( void* pv, ULONG cb, ULONG* pcbRead )
  125. {
  126. size_t dw;
  127. dw = fread( pv, sizeof(char), cb, m_pFile );
  128. if( cb == dw )
  129. {
  130. if( pcbRead != NULL )
  131. {
  132. *pcbRead = cb;
  133. }
  134. return S_OK;
  135. }
  136. return E_FAIL ;
  137. }
  138. STDMETHODIMP CFileStream::Write( const void* pv, ULONG cb, ULONG* pcbWritten )
  139. {
  140. if( cb == fwrite( pv, sizeof(char), cb, m_pFile ))
  141. {
  142. if( pcbWritten != NULL )
  143. {
  144. *pcbWritten = cb;
  145. }
  146. return S_OK;
  147. }
  148. Trace(1, "Error: An error occurred writing to %S.", m_wszFileName);
  149. return STG_E_MEDIUMFULL;
  150. }
  151. STDMETHODIMP CFileStream::Seek( LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition )
  152. {
  153. // fseek can't handle a LARGE_INTEGER seek...
  154. long lOffset;
  155. lOffset = dlibMove.LowPart;
  156. int i = fseek( m_pFile, lOffset, dwOrigin );
  157. if( i )
  158. {
  159. Trace(1, "Error: An error occurred while seeking in the file %S.\n", m_wszFileName);
  160. return E_FAIL;
  161. }
  162. if( plibNewPosition != NULL )
  163. {
  164. plibNewPosition->QuadPart = ftell( m_pFile );
  165. }
  166. return S_OK;
  167. }
  168. STDMETHODIMP CFileStream::SetSize( ULARGE_INTEGER /*libNewSize*/ )
  169. {
  170. return E_NOTIMPL;
  171. }
  172. STDMETHODIMP CFileStream::CopyTo( IStream* /*pstm */, ULARGE_INTEGER /*cb*/,
  173. ULARGE_INTEGER* /*pcbRead*/,
  174. ULARGE_INTEGER* /*pcbWritten*/ )
  175. {
  176. return E_NOTIMPL;
  177. }
  178. STDMETHODIMP CFileStream::Commit( DWORD /*grfCommitFlags*/ )
  179. {
  180. return E_NOTIMPL;
  181. }
  182. STDMETHODIMP CFileStream::Revert()
  183. {
  184. return E_NOTIMPL;
  185. }
  186. STDMETHODIMP CFileStream::LockRegion( ULARGE_INTEGER /*libOffset*/, ULARGE_INTEGER /*cb*/,
  187. DWORD /*dwLockType*/ )
  188. {
  189. return E_NOTIMPL;
  190. }
  191. STDMETHODIMP CFileStream::UnlockRegion( ULARGE_INTEGER /*libOffset*/, ULARGE_INTEGER /*cb*/,
  192. DWORD /*dwLockType*/)
  193. {
  194. return E_NOTIMPL;
  195. }
  196. STDMETHODIMP CFileStream::Stat( STATSTG* /*pstatstg*/, DWORD /*grfStatFlag*/ )
  197. {
  198. return E_NOTIMPL;
  199. }
  200. STDMETHODIMP CFileStream::Clone( IStream** pStream )
  201. {
  202. HRESULT hr = E_OUTOFMEMORY;
  203. CFileStream *pNewStream = new CFileStream( m_pLoader );
  204. if (pNewStream)
  205. {
  206. hr = pNewStream->Open(m_wszFileName,GENERIC_READ);
  207. if (SUCCEEDED(hr))
  208. {
  209. LARGE_INTEGER dlibMove;
  210. dlibMove.QuadPart = 0;
  211. ULARGE_INTEGER libNewPosition;
  212. Seek( dlibMove, STREAM_SEEK_CUR, &libNewPosition );
  213. dlibMove.QuadPart = libNewPosition.QuadPart;
  214. pNewStream->Seek(dlibMove,STREAM_SEEK_SET,NULL);
  215. *pStream = (IStream *) pNewStream;
  216. }
  217. else
  218. {
  219. pNewStream->Release();
  220. }
  221. }
  222. return hr;
  223. }
  224. #else
  225. CFileStream::CFileStream(CLoader *pLoader)
  226. {
  227. m_cRef = 1;
  228. m_hFile = NULL;
  229. m_pLoader = pLoader;
  230. if (pLoader)
  231. {
  232. pLoader->AddRefP();
  233. }
  234. }
  235. CFileStream::~CFileStream()
  236. {
  237. if (m_pLoader)
  238. {
  239. m_pLoader->ReleaseP();
  240. }
  241. Close();
  242. }
  243. HRESULT CFileStream::Open(WCHAR * lpFileName, DWORD dwDesiredAccess)
  244. {
  245. Close();
  246. m_hFile = CreateFile(lpFileName, dwDesiredAccess, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  247. if(m_hFile == NULL || m_hFile == INVALID_HANDLE_VALUE)
  248. {
  249. #ifdef DBG
  250. LPVOID lpMsgBuf;
  251. if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  252. NULL,
  253. GetLastError(),
  254. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  255. (LPTSTR) &lpMsgBuf,
  256. 0,
  257. NULL))
  258. {
  259. Trace(1, "Error: The file %S couldn't be opened: %S\n", lpFileName, lpMsgBuf);
  260. LocalFree( lpMsgBuf );
  261. }
  262. #endif
  263. return DMUS_E_LOADER_FAILEDOPEN;
  264. }
  265. return S_OK;
  266. }
  267. HRESULT CFileStream::Close()
  268. {
  269. if(m_hFile)
  270. {
  271. CloseHandle(m_hFile);
  272. }
  273. m_hFile = NULL;
  274. return S_OK;
  275. }
  276. STDMETHODIMP CFileStream::QueryInterface(const IID &riid, void **ppvObj)
  277. {
  278. if(riid == IID_IUnknown || riid == IID_IStream)
  279. {
  280. *ppvObj = static_cast<IStream*>(this);
  281. AddRef();
  282. return S_OK;
  283. }
  284. else if(riid == IID_IDirectMusicGetLoader)
  285. {
  286. *ppvObj = static_cast<IDirectMusicGetLoader*>(this);
  287. AddRef();
  288. return S_OK;
  289. }
  290. *ppvObj = NULL;
  291. return E_NOINTERFACE;
  292. }
  293. STDMETHODIMP CFileStream::GetLoader(
  294. IDirectMusicLoader ** ppLoader)
  295. {
  296. if(m_pLoader)
  297. {
  298. return m_pLoader->QueryInterface(IID_IDirectMusicLoader,(void **) ppLoader);
  299. }
  300. assert(false);
  301. *ppLoader = NULL;
  302. return E_NOINTERFACE;
  303. }
  304. STDMETHODIMP_(ULONG) CFileStream::AddRef()
  305. {
  306. return InterlockedIncrement(&m_cRef);
  307. }
  308. STDMETHODIMP_(ULONG) CFileStream::Release()
  309. {
  310. if(!InterlockedDecrement(&m_cRef))
  311. {
  312. delete this;
  313. return 0;
  314. }
  315. return m_cRef;
  316. }
  317. /* IStream methods */
  318. STDMETHODIMP CFileStream::Read(void* pv, ULONG cb, ULONG* pcbRead)
  319. {
  320. if(ReadFile(m_hFile, pv, cb, pcbRead, NULL))
  321. {
  322. return S_OK;
  323. }
  324. return E_FAIL;
  325. }
  326. STDMETHODIMP CFileStream::Write(const void* pv, ULONG cb, ULONG* pcbWritten)
  327. {
  328. if(WriteFile(m_hFile, pv, cb, pcbWritten, NULL))
  329. {
  330. return S_OK;
  331. }
  332. Trace(1, "Error: An error occurred writing to %S.", m_wszFileName);
  333. return STG_E_MEDIUMFULL;
  334. }
  335. STDMETHODIMP CFileStream::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
  336. {
  337. DWORD dw;
  338. dw = SetFilePointer(m_hFile,dlibMove.LowPart, &dlibMove.HighPart, dwOrigin);
  339. if(dw == 0xffffffff && GetLastError() != NO_ERROR)
  340. {
  341. Trace(1, "Error: An error occurred while seeking in the file %S.\n", m_wszFileName);
  342. return E_FAIL;
  343. }
  344. if(plibNewPosition != NULL)
  345. {
  346. plibNewPosition->LowPart = dw;
  347. plibNewPosition->HighPart = dlibMove.HighPart;
  348. }
  349. return S_OK;
  350. }
  351. STDMETHODIMP CFileStream::SetSize(ULARGE_INTEGER /*libNewSize*/)
  352. {
  353. return E_NOTIMPL;
  354. }
  355. STDMETHODIMP CFileStream::CopyTo(IStream* /*pstm */, ULARGE_INTEGER /*cb*/,
  356. ULARGE_INTEGER* /*pcbRead*/,
  357. ULARGE_INTEGER* /*pcbWritten*/)
  358. {
  359. return E_NOTIMPL;
  360. }
  361. STDMETHODIMP CFileStream::Commit(DWORD /*grfCommitFlags*/)
  362. {
  363. return E_NOTIMPL;
  364. }
  365. STDMETHODIMP CFileStream::Revert()
  366. {
  367. return E_NOTIMPL;
  368. }
  369. STDMETHODIMP CFileStream::LockRegion(ULARGE_INTEGER /*libOffset*/, ULARGE_INTEGER /*cb*/,
  370. DWORD /*dwLockType*/)
  371. {
  372. return E_NOTIMPL;
  373. }
  374. STDMETHODIMP CFileStream::UnlockRegion(ULARGE_INTEGER /*libOffset*/, ULARGE_INTEGER /*cb*/,
  375. DWORD /*dwLockType*/)
  376. {
  377. return E_NOTIMPL;
  378. }
  379. STDMETHODIMP CFileStream::Stat(STATSTG* /*pstatstg*/, DWORD /*grfStatFlag*/)
  380. {
  381. return E_NOTIMPL;
  382. }
  383. STDMETHODIMP CFileStream::Clone(IStream** /*ppstm*/)
  384. {
  385. HRESULT hr = E_OUTOFMEMORY;
  386. CFileStream *pNewStream = new CFileStream( m_pLoader );
  387. if (pNewStream)
  388. {
  389. hr = pNewStream->Open(m_wszFileName,GENERIC_READ);
  390. if (SUCCEEDED(hr))
  391. {
  392. LARGE_INTEGER dlibMove;
  393. dlibMove.QuadPart = 0;
  394. ULARGE_INTEGER libNewPosition;
  395. Seek( dlibMove, STREAM_SEEK_CUR, &libNewPosition );
  396. dlibMove.QuadPart = libNewPosition.QuadPart;
  397. pNewStream->Seek(dlibMove,STREAM_SEEK_SET,NULL);
  398. }
  399. else
  400. {
  401. pNewStream->Release();
  402. }
  403. }
  404. return hr;
  405. }
  406. #endif
  407. CMemStream::CMemStream( CLoader *pLoader)
  408. {
  409. m_cRef = 1;
  410. m_pbData = NULL;
  411. m_llLength = 0;
  412. m_llPosition = 0;
  413. m_pLoader = pLoader;
  414. if (pLoader)
  415. {
  416. pLoader->AddRefP();
  417. }
  418. }
  419. CMemStream::CMemStream( CLoader *pLoader,
  420. LONGLONG llLength,
  421. LONGLONG llPosition,
  422. BYTE *pbData)
  423. {
  424. m_cRef = 1;
  425. m_pbData = pbData;
  426. m_llLength = llLength;
  427. m_llPosition = llPosition;
  428. m_pLoader = pLoader;
  429. if (pLoader)
  430. {
  431. pLoader->AddRefP();
  432. }
  433. }
  434. CMemStream::~CMemStream()
  435. {
  436. if (m_pLoader)
  437. {
  438. m_pLoader->ReleaseP();
  439. }
  440. Close();
  441. }
  442. HRESULT CMemStream::Open(BYTE *pbData, LONGLONG llLength)
  443. {
  444. Close();
  445. m_pbData = pbData;
  446. m_llLength = llLength;
  447. m_llPosition = 0;
  448. if ((pbData == NULL) || (llLength == 0))
  449. {
  450. #ifdef DBG
  451. if (pbData)
  452. {
  453. Trace(1, "Error: Attempt to load an object from an invalid block of memory. A DMUS_OBJECTDESC has DMUS_OBJ_MEMORY set but pbMemData is NULL.");
  454. }
  455. else
  456. {
  457. Trace(1, "Error: Attempt to load an object from an invalid block of memory. A DMUS_OBJECTDESC has DMUS_OBJ_MEMORY set but llMemLength is 0.");
  458. }
  459. #endif
  460. return DMUS_E_LOADER_FAILEDOPEN;
  461. }
  462. if (IsBadReadPtr(pbData, (DWORD) llLength))
  463. {
  464. m_pbData = NULL;
  465. m_llLength = 0;
  466. #ifdef DBG
  467. DWORD dwLength = (DWORD) llLength;
  468. Trace(1, "Error: Attempt to load an object from an invalid block of memory. A DMUS_OBJECTDESC has DMUS_OBJ_MEMORY, pbMemData=0x%08x, llMemLength=%lu, which isn't a block that can be read.", pbData, dwLength);
  469. #endif
  470. return DMUS_E_LOADER_FAILEDOPEN;
  471. }
  472. return S_OK;
  473. }
  474. HRESULT CMemStream::Close()
  475. {
  476. m_pbData = NULL;
  477. m_llLength = 0;
  478. return S_OK;
  479. }
  480. STDMETHODIMP CMemStream::QueryInterface( const IID &riid, void **ppvObj )
  481. {
  482. if (riid == IID_IUnknown || riid == IID_IStream) {
  483. *ppvObj = static_cast<IStream*>(this);
  484. AddRef();
  485. return S_OK;
  486. }
  487. else if (riid == IID_IDirectMusicGetLoader)
  488. {
  489. *ppvObj = static_cast<IDirectMusicGetLoader*>(this);
  490. AddRef();
  491. return S_OK;
  492. }
  493. *ppvObj = NULL;
  494. return E_NOINTERFACE;
  495. }
  496. STDMETHODIMP CMemStream::GetLoader(
  497. IDirectMusicLoader ** ppLoader)
  498. {
  499. if (m_pLoader)
  500. {
  501. return m_pLoader->QueryInterface( IID_IDirectMusicLoader,(void **) ppLoader );
  502. }
  503. assert(false);
  504. *ppLoader = NULL;
  505. return E_NOINTERFACE;
  506. }
  507. STDMETHODIMP_(ULONG) CMemStream::AddRef()
  508. {
  509. return InterlockedIncrement(&m_cRef);
  510. }
  511. STDMETHODIMP_(ULONG) CMemStream::Release()
  512. {
  513. if (!InterlockedDecrement(&m_cRef))
  514. {
  515. delete this;
  516. return 0;
  517. }
  518. return m_cRef;
  519. }
  520. /* IStream methods */
  521. STDMETHODIMP CMemStream::Read( void* pv, ULONG cb, ULONG* pcbRead )
  522. {
  523. if ((cb + m_llPosition) <= m_llLength)
  524. {
  525. memcpy(pv,&m_pbData[m_llPosition],cb);
  526. m_llPosition += cb;
  527. if( pcbRead != NULL )
  528. {
  529. *pcbRead = cb;
  530. }
  531. return S_OK;
  532. }
  533. #ifdef DBG
  534. Trace(1, "Error: Unexpected end of data reading object from memory. Memory length is %ld, attempting to read to %ld\n",
  535. (long) m_llLength, (long) (cb + m_llPosition));
  536. #endif
  537. return E_FAIL ;
  538. }
  539. STDMETHODIMP CMemStream::Write( const void* pv, ULONG cb, ULONG* pcbWritten )
  540. {
  541. return E_NOTIMPL;
  542. }
  543. STDMETHODIMP CMemStream::Seek( LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition )
  544. {
  545. // Since we only parse RIFF data, we can't have a file over
  546. // DWORD in length, so disregard high part of LARGE_INTEGER.
  547. LONGLONG llOffset;
  548. llOffset = dlibMove.QuadPart;
  549. if (dwOrigin == STREAM_SEEK_CUR)
  550. {
  551. llOffset += m_llPosition;
  552. }
  553. else if (dwOrigin == STREAM_SEEK_END)
  554. {
  555. llOffset += m_llLength;
  556. }
  557. if ((llOffset >= 0) && (llOffset <= m_llLength))
  558. {
  559. m_llPosition = llOffset;
  560. }
  561. else
  562. {
  563. #ifdef DBG
  564. Trace(1, "Error: Seek request %ld past end of memory file, size %ld.\n",
  565. (long) llOffset, (long) m_llLength);
  566. #endif
  567. return E_FAIL;
  568. }
  569. if( plibNewPosition != NULL )
  570. {
  571. plibNewPosition->QuadPart = m_llPosition;
  572. }
  573. return S_OK;
  574. }
  575. STDMETHODIMP CMemStream::SetSize( ULARGE_INTEGER /*libNewSize*/ )
  576. {
  577. return E_NOTIMPL;
  578. }
  579. STDMETHODIMP CMemStream::CopyTo( IStream* /*pstm */, ULARGE_INTEGER /*cb*/,
  580. ULARGE_INTEGER* /*pcbRead*/,
  581. ULARGE_INTEGER* /*pcbWritten*/ )
  582. {
  583. return E_NOTIMPL;
  584. }
  585. STDMETHODIMP CMemStream::Commit( DWORD /*grfCommitFlags*/ )
  586. {
  587. return E_NOTIMPL;
  588. }
  589. STDMETHODIMP CMemStream::Revert()
  590. {
  591. return E_NOTIMPL;
  592. }
  593. STDMETHODIMP CMemStream::LockRegion( ULARGE_INTEGER /*libOffset*/, ULARGE_INTEGER /*cb*/,
  594. DWORD /*dwLockType*/ )
  595. {
  596. return E_NOTIMPL;
  597. }
  598. STDMETHODIMP CMemStream::UnlockRegion( ULARGE_INTEGER /*libOffset*/, ULARGE_INTEGER /*cb*/,
  599. DWORD /*dwLockType*/)
  600. {
  601. return E_NOTIMPL;
  602. }
  603. STDMETHODIMP CMemStream::Stat( STATSTG* /*pstatstg*/, DWORD /*grfStatFlag*/ )
  604. {
  605. return E_NOTIMPL;
  606. }
  607. STDMETHODIMP CMemStream::Clone( IStream** ppStream )
  608. {
  609. *ppStream = (IStream *) new CMemStream( m_pLoader, m_llLength, m_llPosition, m_pbData );
  610. if (*ppStream)
  611. {
  612. return S_OK;
  613. }
  614. return E_OUTOFMEMORY;
  615. }
  616. STDAPI AllocRIFFStream( IStream* pStream, IRIFFStream** ppRiff )
  617. {
  618. if( ( *ppRiff = (IRIFFStream*) new CRIFFStream( pStream ) ) == NULL )
  619. {
  620. return E_OUTOFMEMORY;
  621. }
  622. return S_OK;
  623. }
  624. STDMETHODIMP CRIFFStream::Descend(LPMMCKINFO lpck, LPMMCKINFO lpckParent, UINT wFlags)
  625. {
  626. assert(lpck);
  627. FOURCC ckidFind; // Chunk ID to find (or NULL)
  628. FOURCC fccTypeFind; // Form/list type to find (or NULL)
  629. // Figure out what chunk id and form/list type for which to search
  630. if(wFlags & MMIO_FINDCHUNK)
  631. {
  632. ckidFind = lpck->ckid;
  633. fccTypeFind = NULL;
  634. }
  635. else if(wFlags & MMIO_FINDRIFF)
  636. {
  637. ckidFind = FOURCC_RIFF;
  638. fccTypeFind = lpck->fccType;
  639. }
  640. else if(wFlags & MMIO_FINDLIST)
  641. {
  642. ckidFind = FOURCC_LIST;
  643. fccTypeFind = lpck->fccType;
  644. }
  645. else
  646. {
  647. ckidFind = fccTypeFind = NULL;
  648. }
  649. lpck->dwFlags = 0L;
  650. for(;;)
  651. {
  652. HRESULT hr;
  653. LARGE_INTEGER li;
  654. ULARGE_INTEGER uli;
  655. ULONG cbRead;
  656. // Read the chunk header
  657. hr = m_pStream->Read(lpck, 2 * sizeof(DWORD), &cbRead);
  658. if (FAILED(hr) || (cbRead != 2 * sizeof(DWORD)))
  659. {
  660. return DMUS_E_DESCEND_CHUNK_FAIL;
  661. }
  662. // Store the offset of the data part of the chunk
  663. li.QuadPart = 0;
  664. hr = m_pStream->Seek(li, STREAM_SEEK_CUR, &uli);
  665. if(FAILED(hr))
  666. {
  667. Trace(1, "Error: Read error - unable to seek in a stream.\n");
  668. return DMUS_E_CANNOTSEEK;
  669. }
  670. else
  671. {
  672. lpck->dwDataOffset = uli.LowPart;
  673. }
  674. // See if the chunk is within the parent chunk (if given)
  675. if((lpckParent != NULL) &&
  676. (lpck->dwDataOffset - 8L >=
  677. lpckParent->dwDataOffset + lpckParent->cksize))
  678. {
  679. return DMUS_E_DESCEND_CHUNK_FAIL;
  680. }
  681. // If the chunk is a 'RIFF' or 'LIST' chunk, read the
  682. // form type or list type
  683. if((lpck->ckid == FOURCC_RIFF) || (lpck->ckid == FOURCC_LIST))
  684. {
  685. hr = m_pStream->Read(&lpck->fccType, sizeof(DWORD), &cbRead);
  686. if(FAILED(hr) || (cbRead != sizeof(DWORD)))
  687. {
  688. return DMUS_E_DESCEND_CHUNK_FAIL;
  689. }
  690. }
  691. else
  692. {
  693. lpck->fccType = NULL;
  694. }
  695. // If this is the chunk we're looking for, stop looking
  696. if(((ckidFind == NULL) || (ckidFind == lpck->ckid)) &&
  697. ((fccTypeFind == NULL) || (fccTypeFind == lpck->fccType)))
  698. {
  699. break;
  700. }
  701. // Ascend out of the chunk and try again
  702. HRESULT w = Ascend(lpck, 0);
  703. if(FAILED(w))
  704. {
  705. return w;
  706. }
  707. }
  708. return S_OK;
  709. }
  710. //////////////////////////////////////////////////////////////////////
  711. // CRIFFStream::Ascend
  712. STDMETHODIMP CRIFFStream::Ascend(LPMMCKINFO lpck, UINT /*wFlags*/)
  713. {
  714. assert(lpck);
  715. HRESULT hr;
  716. LARGE_INTEGER li;
  717. ULARGE_INTEGER uli;
  718. if (lpck->dwFlags & MMIO_DIRTY)
  719. {
  720. // <lpck> refers to a chunk created by CreateChunk();
  721. // check that the chunk size that was written when
  722. // CreateChunk() was called is the real chunk size;
  723. // if not, fix it
  724. LONG lOffset; // current offset in file
  725. LONG lActualSize; // actual size of chunk data
  726. li.QuadPart = 0;
  727. hr = m_pStream->Seek(li, STREAM_SEEK_CUR, &uli);
  728. if(FAILED(hr))
  729. {
  730. Trace(1, "Error: Read error - unable to seek in a stream.\n");
  731. return DMUS_E_CANNOTSEEK;
  732. }
  733. else
  734. {
  735. lOffset = uli.LowPart;
  736. }
  737. if((lActualSize = lOffset - lpck->dwDataOffset) < 0)
  738. {
  739. Trace(1, "Error: Unable to write to a stream.\n");
  740. return DMUS_E_CANNOTWRITE;
  741. }
  742. if(LOWORD(lActualSize) & 1)
  743. {
  744. ULONG cbWritten;
  745. // Chunk size is odd -- write a null pad byte
  746. hr = m_pStream->Write("\0", 1, &cbWritten);
  747. if(FAILED(hr) || cbWritten != 1)
  748. {
  749. Trace(1, "Error: Unable to write to a stream.\n");
  750. return DMUS_E_CANNOTWRITE;
  751. }
  752. }
  753. if(lpck->cksize == (DWORD)lActualSize)
  754. {
  755. return S_OK;
  756. }
  757. // Fix the chunk header
  758. lpck->cksize = lActualSize;
  759. li.QuadPart = lpck->dwDataOffset - sizeof(DWORD);
  760. hr = m_pStream->Seek(li, STREAM_SEEK_SET, &uli);
  761. if(FAILED(hr))
  762. {
  763. Trace(1, "Error: Read error - unable to seek in a stream.\n");
  764. return DMUS_E_CANNOTSEEK;
  765. }
  766. ULONG cbWritten;
  767. hr = m_pStream->Write(&lpck->cksize, sizeof(DWORD), &cbWritten);
  768. if(FAILED(hr) || cbWritten != sizeof(DWORD))
  769. {
  770. Trace(1, "Error: Unable to write to a stream.\n");
  771. return DMUS_E_CANNOTWRITE;
  772. }
  773. }
  774. // Seek to the end of the chunk, past the null pad byte
  775. // (which is only there if chunk size is odd)
  776. li.QuadPart = lpck->dwDataOffset + lpck->cksize + (lpck->cksize & 1L);
  777. hr = m_pStream->Seek(li, STREAM_SEEK_SET, &uli);
  778. if(FAILED(hr))
  779. {
  780. Trace(1, "Error: Read error - unable to seek in a stream.\n");
  781. return DMUS_E_CANNOTSEEK;
  782. }
  783. return S_OK;
  784. }
  785. //////////////////////////////////////////////////////////////////////
  786. // CRIFFStream::CreateChunk
  787. STDMETHODIMP CRIFFStream::CreateChunk(LPMMCKINFO lpck, UINT wFlags)
  788. {
  789. assert(lpck);
  790. UINT iBytes; // Bytes to write
  791. LONG lOffset; // Current offset in file
  792. // Store the offset of the data part of the chunk
  793. LARGE_INTEGER li;
  794. ULARGE_INTEGER uli;
  795. li.QuadPart = 0;
  796. HRESULT hr = m_pStream->Seek(li, STREAM_SEEK_CUR, &uli);
  797. if(FAILED(hr))
  798. {
  799. Trace(1, "Error: Read error - unable to seek in a stream.\n");
  800. return DMUS_E_CANNOTSEEK;
  801. }
  802. else
  803. {
  804. lOffset = uli.LowPart;
  805. }
  806. lpck->dwDataOffset = lOffset + 2 * sizeof(DWORD);
  807. // figure out if a form/list type needs to be written
  808. if(wFlags & MMIO_CREATERIFF)
  809. {
  810. lpck->ckid = FOURCC_RIFF, iBytes = 3 * sizeof(DWORD);
  811. }
  812. else if(wFlags & MMIO_CREATELIST)
  813. {
  814. lpck->ckid = FOURCC_LIST, iBytes = 3 * sizeof(DWORD);
  815. }
  816. else
  817. {
  818. iBytes = 2 * sizeof(DWORD);
  819. }
  820. // Write the chunk header
  821. ULONG cbWritten;
  822. hr = m_pStream->Write(lpck, iBytes, &cbWritten);
  823. if(FAILED(hr) || cbWritten != iBytes)
  824. {
  825. Trace(1, "Error: Unable to write to a stream.\n");
  826. return DMUS_E_CANNOTWRITE;
  827. }
  828. lpck->dwFlags = MMIO_DIRTY;
  829. return S_OK;
  830. }
  831. CStream::CStream( CLoader *pLoader, IStream *pStream )
  832. {
  833. m_cRef = 1;
  834. m_pIStream = pStream;
  835. if (pStream)
  836. {
  837. pStream->AddRef();
  838. }
  839. m_pLoader = pLoader;
  840. if (pLoader)
  841. {
  842. pLoader->AddRefP();
  843. }
  844. }
  845. CStream::CStream( CLoader *pLoader)
  846. {
  847. m_cRef = 1;
  848. m_pIStream = NULL;
  849. m_pLoader = pLoader;
  850. if (pLoader)
  851. {
  852. pLoader->AddRefP();
  853. }
  854. }
  855. CStream::~CStream()
  856. {
  857. if (m_pLoader)
  858. {
  859. m_pLoader->ReleaseP();
  860. }
  861. Close();
  862. }
  863. HRESULT CStream::Open(IStream *pIStream,LARGE_INTEGER liStartPosition)
  864. {
  865. Close();
  866. m_pIStream = pIStream;
  867. if (m_pIStream)
  868. {
  869. // Need to seek to point that was where we were in the stream
  870. // when the stream was first provided via GetObject or SetObject.
  871. pIStream->Seek(liStartPosition,STREAM_SEEK_SET,NULL);
  872. pIStream->AddRef();
  873. }
  874. return S_OK;
  875. }
  876. HRESULT CStream::Close()
  877. {
  878. if (m_pIStream)
  879. {
  880. m_pIStream->Release();
  881. }
  882. m_pIStream = NULL;
  883. return S_OK;
  884. }
  885. STDMETHODIMP CStream::QueryInterface( const IID &riid, void **ppvObj )
  886. {
  887. if (riid == IID_IUnknown || riid == IID_IStream) {
  888. *ppvObj = static_cast<IStream*>(this);
  889. AddRef();
  890. return S_OK;
  891. }
  892. else if (riid == IID_IDirectMusicGetLoader)
  893. {
  894. *ppvObj = static_cast<IDirectMusicGetLoader*>(this);
  895. AddRef();
  896. return S_OK;
  897. }
  898. *ppvObj = NULL;
  899. return E_NOINTERFACE;
  900. }
  901. STDMETHODIMP CStream::GetLoader(
  902. IDirectMusicLoader ** ppLoader)
  903. {
  904. if (m_pLoader)
  905. {
  906. return m_pLoader->QueryInterface( IID_IDirectMusicLoader,(void **) ppLoader );
  907. }
  908. assert(false);
  909. *ppLoader = NULL;
  910. return E_NOINTERFACE;
  911. }
  912. STDMETHODIMP_(ULONG) CStream::AddRef()
  913. {
  914. return InterlockedIncrement(&m_cRef);
  915. }
  916. STDMETHODIMP_(ULONG) CStream::Release()
  917. {
  918. if (!InterlockedDecrement(&m_cRef))
  919. {
  920. Close();
  921. delete this;
  922. return 0;
  923. }
  924. return m_cRef;
  925. }
  926. /* IStream methods */
  927. STDMETHODIMP CStream::Read( void* pv, ULONG cb, ULONG* pcbRead )
  928. {
  929. if (m_pIStream)
  930. {
  931. return m_pIStream->Read(pv, cb, pcbRead);
  932. }
  933. Trace(1, "Error: Attempt to read from a NULL stream.\n");
  934. return E_FAIL;
  935. }
  936. STDMETHODIMP CStream::Write( const void* pv, ULONG cb, ULONG* pcbWritten )
  937. {
  938. if (m_pIStream)
  939. {
  940. return m_pIStream->Write(pv, cb, pcbWritten);
  941. }
  942. Trace(1, "Error: Attempt to write to a NULL stream.\n");
  943. return E_FAIL;
  944. }
  945. STDMETHODIMP CStream::Seek( LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition )
  946. {
  947. if (m_pIStream)
  948. {
  949. return m_pIStream->Seek(dlibMove, dwOrigin, plibNewPosition);
  950. }
  951. Trace(1, "Error: Read error - attempt to seek in a NULL stream.\n");
  952. return E_FAIL;
  953. }
  954. STDMETHODIMP CStream::SetSize( ULARGE_INTEGER libNewSize)
  955. {
  956. if (m_pIStream)
  957. {
  958. return m_pIStream->SetSize(libNewSize);
  959. }
  960. return E_FAIL;
  961. }
  962. STDMETHODIMP CStream::CopyTo( IStream* pstm, ULARGE_INTEGER cb,
  963. ULARGE_INTEGER* pcbRead,
  964. ULARGE_INTEGER* pcbWritten)
  965. {
  966. if (m_pIStream)
  967. {
  968. return m_pIStream->CopyTo(pstm, cb, pcbRead, pcbWritten);
  969. }
  970. return E_FAIL;
  971. }
  972. STDMETHODIMP CStream::Commit( DWORD grfCommitFlags)
  973. {
  974. if (m_pIStream)
  975. {
  976. return m_pIStream->Commit(grfCommitFlags);
  977. }
  978. return E_FAIL;
  979. }
  980. STDMETHODIMP CStream::Revert()
  981. {
  982. if (m_pIStream)
  983. {
  984. return m_pIStream->Revert();
  985. }
  986. return E_FAIL;
  987. }
  988. STDMETHODIMP CStream::LockRegion( ULARGE_INTEGER libOffset, ULARGE_INTEGER cb,
  989. DWORD dwLockType)
  990. {
  991. if (m_pIStream)
  992. {
  993. return m_pIStream->LockRegion(libOffset, cb, dwLockType);
  994. }
  995. return E_FAIL;
  996. }
  997. STDMETHODIMP CStream::UnlockRegion( ULARGE_INTEGER libOffset, ULARGE_INTEGER cb,
  998. DWORD dwLockType)
  999. {
  1000. if (m_pIStream)
  1001. {
  1002. return m_pIStream->UnlockRegion(libOffset, cb, dwLockType);
  1003. }
  1004. return E_FAIL;
  1005. }
  1006. STDMETHODIMP CStream::Stat( STATSTG* pstatstg, DWORD grfStatFlag)
  1007. {
  1008. if (m_pIStream)
  1009. {
  1010. return m_pIStream->Stat(pstatstg, grfStatFlag);
  1011. }
  1012. return E_FAIL;
  1013. }
  1014. STDMETHODIMP CStream::Clone( IStream** ppStream)
  1015. {
  1016. HRESULT hr = E_FAIL;
  1017. if (m_pIStream)
  1018. {
  1019. IStream *pNewIStream = NULL;
  1020. hr = m_pIStream->Clone(&pNewIStream);
  1021. if (SUCCEEDED(hr))
  1022. {
  1023. CStream *pNewCStream = new CStream( m_pLoader, pNewIStream );
  1024. if (pNewCStream)
  1025. {
  1026. *ppStream = (IStream *) pNewCStream;
  1027. hr = S_OK;
  1028. }
  1029. else
  1030. {
  1031. hr = E_OUTOFMEMORY;
  1032. }
  1033. pNewIStream->Release();
  1034. }
  1035. }
  1036. else
  1037. {
  1038. Trace(1, "Error: Attempt to clone a NULL stream.\n");
  1039. }
  1040. return hr;
  1041. }