Source code of Windows XP (NT5)
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.

209 lines
5.8 KiB

  1. // stream.cpp
  2. // Copyright (C) 1997, 1998 Microsoft Corporation. All Rights Reserved
  3. //
  4. // @doc EXTERNAL
  5. #include <objbase.h>
  6. #include <mmsystem.h>
  7. #include <dsoundp.h>
  8. #include "debug.h"
  9. #include "dmusicc.h"
  10. #include "dmusici.h"
  11. #include "riff.h"
  12. #include "dswave.h"
  13. STDAPI AllocRIFFStream( IStream* pStream, IRIFFStream** ppRiff )
  14. {
  15. if( ( *ppRiff = (IRIFFStream*) new CRIFFStream( pStream ) ) == NULL )
  16. {
  17. return E_OUTOFMEMORY;
  18. }
  19. return S_OK;
  20. }
  21. /* MyRead, MyWrite, MySeek
  22. *
  23. * These are functionally identical to mmioRead, mmioWrite, and mmioSeek,
  24. * except for the absence of the HMMIO parameter.
  25. */
  26. long CRIFFStream::MyRead(void *pv, long cb)
  27. {
  28. ULONG cbRead;
  29. if (FAILED(m_pStream->Read(pv, cb, &cbRead)))
  30. return -1;
  31. return cbRead;
  32. }
  33. long CRIFFStream::MyWrite(const void *pv, long cb)
  34. {
  35. ULONG cbWritten;
  36. if (FAILED(m_pStream->Write(pv, cb, &cbWritten)))
  37. return -1;
  38. return cbWritten;
  39. }
  40. long CRIFFStream::MySeek(long lOffset, int iOrigin)
  41. {
  42. LARGE_INTEGER dlibSeekTo;
  43. ULARGE_INTEGER dlibNewPos;
  44. dlibSeekTo.HighPart = 0;
  45. dlibSeekTo.LowPart = lOffset;
  46. if (FAILED(m_pStream->Seek(dlibSeekTo, iOrigin, &dlibNewPos)))
  47. return -1;
  48. return dlibNewPos.LowPart;
  49. }
  50. UINT CRIFFStream::Descend(LPMMCKINFO lpck, LPMMCKINFO lpckParent, UINT wFlags)
  51. {
  52. FOURCC ckidFind; // chunk ID to find (or NULL)
  53. FOURCC fccTypeFind; // form/list type to find (or NULL)
  54. /* figure out what chunk id and form/list type to search for */
  55. if (wFlags & MMIO_FINDCHUNK)
  56. ckidFind = lpck->ckid, fccTypeFind = NULL;
  57. else
  58. if (wFlags & MMIO_FINDRIFF)
  59. ckidFind = FOURCC_RIFF, fccTypeFind = lpck->fccType;
  60. else
  61. if (wFlags & MMIO_FINDLIST)
  62. ckidFind = FOURCC_LIST, fccTypeFind = lpck->fccType;
  63. else
  64. ckidFind = fccTypeFind = NULL;
  65. lpck->dwFlags = 0L;
  66. for(;;)
  67. {
  68. UINT w;
  69. /* read the chunk header */
  70. if (MyRead(lpck, 2 * sizeof(DWORD)) !=
  71. 2 * sizeof(DWORD))
  72. return MMIOERR_CHUNKNOTFOUND;
  73. FixBytes( FBT_LONG, &lpck->cksize );
  74. /* store the offset of the data part of the chunk */
  75. if ((lpck->dwDataOffset = MySeek(0L, SEEK_CUR)) == -1)
  76. return MMIOERR_CANNOTSEEK;
  77. /* see if the chunk is within the parent chunk (if given) */
  78. if ((lpckParent != NULL) &&
  79. (lpck->dwDataOffset - 8L >=
  80. lpckParent->dwDataOffset + lpckParent->cksize))
  81. return MMIOERR_CHUNKNOTFOUND;
  82. /* if the chunk if a 'RIFF' or 'LIST' chunk, read the
  83. * form type or list type
  84. */
  85. if ((lpck->ckid == FOURCC_RIFF) || (lpck->ckid == FOURCC_LIST))
  86. {
  87. if (MyRead(&lpck->fccType,
  88. sizeof(DWORD)) != sizeof(DWORD))
  89. return MMIOERR_CHUNKNOTFOUND;
  90. }
  91. else
  92. lpck->fccType = NULL;
  93. /* if this is the chunk we're looking for, stop looking */
  94. if ( ((ckidFind == NULL) || (ckidFind == lpck->ckid)) &&
  95. ((fccTypeFind == NULL) || (fccTypeFind == lpck->fccType)) )
  96. break;
  97. /* ascend out of the chunk and try again */
  98. if ((w = Ascend(lpck, 0)) != 0)
  99. return w;
  100. }
  101. return 0;
  102. }
  103. UINT CRIFFStream::Ascend(LPMMCKINFO lpck, UINT /*wFlags*/)
  104. {
  105. if (lpck->dwFlags & MMIO_DIRTY)
  106. {
  107. /* <lpck> refers to a chunk created by CreateChunk();
  108. * check that the chunk size that was written when
  109. * CreateChunk() was called is the real chunk size;
  110. * if not, fix it
  111. */
  112. LONG lOffset; // current offset in file
  113. LONG lActualSize; // actual size of chunk data
  114. if ((lOffset = MySeek(0L, SEEK_CUR)) == -1)
  115. return MMIOERR_CANNOTSEEK;
  116. if ((lActualSize = lOffset - lpck->dwDataOffset) < 0)
  117. return MMIOERR_CANNOTWRITE;
  118. if (LOWORD(lActualSize) & 1)
  119. {
  120. /* chunk size is odd -- write a null pad byte */
  121. if (MyWrite("\0", 1) != 1)
  122. return MMIOERR_CANNOTWRITE;
  123. }
  124. if (lpck->cksize == (DWORD)lActualSize)
  125. return 0;
  126. /* fix the chunk header */
  127. lpck->cksize = lActualSize;
  128. if (MySeek(lpck->dwDataOffset - sizeof(DWORD), SEEK_SET) == -1)
  129. return MMIOERR_CANNOTSEEK;
  130. FixBytes( FBT_LONG, &lpck->cksize );
  131. if (MyWrite(&lpck->cksize, sizeof(DWORD)) != sizeof(DWORD)) {
  132. FixBytes( FBT_LONG, &lpck->cksize );
  133. return MMIOERR_CANNOTWRITE;
  134. }
  135. FixBytes( FBT_LONG, &lpck->cksize );
  136. }
  137. /* seek to the end of the chunk, past the null pad byte
  138. * (which is only there if chunk size is odd)
  139. */
  140. if (MySeek(lpck->dwDataOffset + lpck->cksize + (lpck->cksize & 1L),
  141. SEEK_SET) == -1)
  142. return MMIOERR_CANNOTSEEK;
  143. return 0;
  144. }
  145. UINT CRIFFStream::CreateChunk(LPMMCKINFO lpck, UINT wFlags)
  146. {
  147. int iBytes; // bytes to write
  148. LONG lOffset; // current offset in file
  149. /* store the offset of the data part of the chunk */
  150. if ((lOffset = MySeek(0L, SEEK_CUR)) == -1)
  151. return MMIOERR_CANNOTSEEK;
  152. lpck->dwDataOffset = lOffset + 2 * sizeof(DWORD);
  153. /* figure out if a form/list type needs to be written */
  154. if (wFlags & MMIO_CREATERIFF)
  155. lpck->ckid = FOURCC_RIFF, iBytes = 3 * sizeof(DWORD);
  156. else
  157. if (wFlags & MMIO_CREATELIST)
  158. lpck->ckid = FOURCC_LIST, iBytes = 3 * sizeof(DWORD);
  159. else
  160. iBytes = 2 * sizeof(DWORD);
  161. /* write the chunk header */
  162. FixBytes( FBT_MMCKINFO, lpck );
  163. if (MyWrite(lpck, (LONG) iBytes) != (LONG) iBytes) {
  164. FixBytes( FBT_MMCKINFO, lpck );
  165. return MMIOERR_CANNOTWRITE;
  166. }
  167. FixBytes( FBT_MMCKINFO, lpck );
  168. lpck->dwFlags = MMIO_DIRTY;
  169. return 0;
  170. }