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.

363 lines
10 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. CRiffParser::CRiffParser(IStream *pStream)
  11. {
  12. assert(pStream);
  13. m_fDebugOn = FALSE;
  14. m_pStream = pStream;
  15. m_pParent = NULL;
  16. m_pChunk = NULL;
  17. m_lRead = 0;
  18. m_fFirstPass = TRUE;
  19. m_fComponentFailed = FALSE;
  20. m_fInComponent = FALSE;
  21. }
  22. void CRiffParser::EnterList(RIFFIO *pChunk)
  23. {
  24. assert (pChunk);
  25. pChunk->lRead = 0;
  26. pChunk->pParent = m_pChunk; // Previous chunk (could be NULL.)
  27. m_pParent = m_pChunk;
  28. m_pChunk = pChunk;
  29. m_fFirstPass = TRUE;
  30. }
  31. void CRiffParser::LeaveList()
  32. {
  33. assert (m_pChunk);
  34. if (m_pChunk)
  35. {
  36. m_pChunk = m_pChunk->pParent;
  37. if (m_pChunk)
  38. {
  39. m_pParent = m_pChunk->pParent;
  40. }
  41. }
  42. }
  43. BOOL CRiffParser::NextChunk(HRESULT * pHr)
  44. {
  45. BOOL fMore = FALSE;
  46. if (SUCCEEDED(*pHr))
  47. {
  48. // If this is the first time we've entered this list, there is no previous chunk.
  49. if (m_fFirstPass)
  50. {
  51. // Clear the flag.
  52. m_fFirstPass = FALSE;
  53. }
  54. else
  55. {
  56. // Clean up the previous pass.
  57. *pHr = LeaveChunk();
  58. }
  59. // Find out if there are more chunks to read.
  60. fMore = MoreChunks();
  61. // If so, and we don't have any failure, go ahead and read the next chunk header.
  62. if (fMore && SUCCEEDED(*pHr))
  63. {
  64. *pHr = EnterChunk();
  65. }
  66. }
  67. else
  68. {
  69. #ifdef DBG
  70. char szName[5];
  71. if (m_fDebugOn)
  72. {
  73. szName[4] = 0;
  74. strncpy(szName,(char *)&m_pChunk->ckid,4);
  75. Trace(0,"Error parsing %s, Read %ld of %ld\n",szName,m_pChunk->lRead,RIFF_ALIGN(m_pChunk->cksize));
  76. }
  77. #endif
  78. // If we were in a component, it's okay to fail. Mark that fact by setting
  79. // m_fComponentFailed then properly pull out of the chunk so we can
  80. // continue reading.
  81. if (m_fInComponent)
  82. {
  83. m_fComponentFailed = TRUE;
  84. // We don't need to check for first pass, because we must have gotten
  85. // that far. Instead, we just clean up from the failed chunk.
  86. // Note that this sets the hresult to S_OK, which is what we want.
  87. // Later, the caller needs to call ComponentFailed() to find out if
  88. // this error occured.
  89. *pHr = LeaveChunk();
  90. }
  91. else
  92. {
  93. // Clean up but leave the error code.
  94. LeaveChunk();
  95. }
  96. }
  97. return fMore && SUCCEEDED(*pHr);
  98. }
  99. BOOL CRiffParser::MoreChunks()
  100. {
  101. assert(m_pChunk);
  102. if (m_pChunk)
  103. {
  104. if (m_pParent)
  105. {
  106. // Return TRUE if there's enough room for another chunk.
  107. return (m_pParent->lRead < (m_pParent->cksize - 8));
  108. }
  109. else
  110. {
  111. // This must be a top level chunk, in which case there would only be one to read.
  112. return (m_pChunk->lRead == 0);
  113. }
  114. }
  115. // This should never happen unless CRiffParser is used incorrectly, in which
  116. // case the assert will help debug. But, in the interest of making Prefix happy...
  117. return false;
  118. }
  119. HRESULT CRiffParser::EnterChunk()
  120. {
  121. assert(m_pChunk);
  122. if (m_pChunk)
  123. {
  124. // Read the chunk header
  125. HRESULT hr = m_pStream->Read(m_pChunk, 2 * sizeof(DWORD), NULL);
  126. if (SUCCEEDED(hr) && (long)m_pChunk->cksize < 0)
  127. {
  128. // This size is clearly too big for a valid chunk.
  129. hr = DMUS_E_DESCEND_CHUNK_FAIL;
  130. }
  131. if (SUCCEEDED(hr))
  132. {
  133. #ifdef DBG
  134. char szName[5];
  135. if (m_fDebugOn)
  136. {
  137. szName[4] = 0;
  138. strncpy(szName,(char *)&m_pChunk->ckid,4);
  139. ULARGE_INTEGER ul;
  140. LARGE_INTEGER li;
  141. li.QuadPart = 0;
  142. m_pStream->Seek(li, STREAM_SEEK_CUR, &ul);
  143. Trace(0,"Entering %s, Length %ld, File position is %ld",szName,m_pChunk->cksize,(long)ul.QuadPart);
  144. }
  145. #endif
  146. // Clear bytes read field.
  147. m_pChunk->lRead = 0;
  148. // Check to see if this is a container (LIST or RIFF.)
  149. if((m_pChunk->ckid == FOURCC_RIFF) || (m_pChunk->ckid == FOURCC_LIST))
  150. {
  151. hr = m_pStream->Read(&m_pChunk->fccType, sizeof(DWORD), NULL);
  152. if (SUCCEEDED(hr))
  153. {
  154. m_pChunk->lRead += sizeof(DWORD);
  155. #ifdef DBG
  156. if (m_fDebugOn)
  157. {
  158. strncpy(szName,(char *)&m_pChunk->fccType,4);
  159. Trace(0," Type %s",szName);
  160. }
  161. #endif
  162. }
  163. else
  164. {
  165. Trace(1,"Error: Unable to read file.\n");
  166. }
  167. }
  168. #ifdef DBG
  169. if (m_fDebugOn) Trace(0,"\n");
  170. #endif
  171. }
  172. else
  173. {
  174. Trace(1,"Error: Unable to read file.\n");
  175. }
  176. return hr;
  177. }
  178. // This should never happen unless CRiffParser is used incorrectly, in which
  179. // case the assert will help debug. But, in the interest of making Prefix happy...
  180. return E_FAIL;
  181. }
  182. HRESULT CRiffParser::LeaveChunk()
  183. {
  184. HRESULT hr = S_OK;
  185. assert(m_pChunk);
  186. if (m_pChunk)
  187. {
  188. m_fInComponent = false;
  189. // Get the rounded up size of the chunk.
  190. long lSize = RIFF_ALIGN(m_pChunk->cksize);
  191. // Increment the parent's count of bytes read so far.
  192. if (m_pParent)
  193. {
  194. m_pParent->lRead += lSize + (2 * sizeof(DWORD));
  195. if (m_pParent->lRead > RIFF_ALIGN(m_pParent->cksize))
  196. {
  197. Trace(1,"Error: Unable to read file.\n");
  198. hr = DMUS_E_DESCEND_CHUNK_FAIL; // Goofy error name, but need to be consistent with previous versions.
  199. }
  200. }
  201. #ifdef DBG
  202. char szName[5];
  203. if (m_fDebugOn)
  204. {
  205. szName[4] = 0;
  206. strncpy(szName,(char *)&m_pChunk->ckid,4);
  207. ULARGE_INTEGER ul;
  208. LARGE_INTEGER li;
  209. li.QuadPart = 0;
  210. m_pStream->Seek(li, STREAM_SEEK_CUR, &ul);
  211. Trace(0,"Leaving %s, Read %ld of %ld, File Position is %ld\n",szName,m_pChunk->lRead,lSize,(long)ul.QuadPart);
  212. }
  213. #endif
  214. // If we haven't actually read this entire chunk, seek to the end of it.
  215. if (m_pChunk->lRead < lSize)
  216. {
  217. LARGE_INTEGER li;
  218. li.QuadPart = lSize - m_pChunk->lRead;
  219. hr = m_pStream->Seek(li,STREAM_SEEK_CUR,NULL);
  220. // There's a chance it could fail because we are at the end of file with an odd length chunk.
  221. if (FAILED(hr))
  222. {
  223. // If there's a parent, see if this is the last chunk.
  224. if (m_pParent)
  225. {
  226. if (m_pParent->cksize >= (m_pParent->lRead - 1))
  227. {
  228. hr = S_OK;
  229. }
  230. }
  231. // Else, see if we are an odd length.
  232. else if (m_pChunk->cksize & 1)
  233. {
  234. hr = S_OK;
  235. }
  236. }
  237. }
  238. return hr;
  239. }
  240. // This should never happen unless CRiffParser is used incorrectly, in which
  241. // case the assert will help debug. But, in the interest of making Prefix happy...
  242. return E_FAIL;
  243. }
  244. HRESULT CRiffParser::Read(void *pv,ULONG cb)
  245. {
  246. assert(m_pChunk);
  247. if (m_pChunk)
  248. {
  249. // Make sure we don't read beyond the end of the chunk.
  250. if (((long)cb + m_pChunk->lRead) > m_pChunk->cksize)
  251. {
  252. cb -= (cb - (m_pChunk->cksize - m_pChunk->lRead));
  253. }
  254. HRESULT hr = m_pStream->Read(pv,cb,NULL);
  255. if (SUCCEEDED(hr))
  256. {
  257. m_pChunk->lRead += cb;
  258. }
  259. else
  260. {
  261. Trace(1,"Error: Unable to read %ld bytes from file.\n",cb);
  262. }
  263. return hr;
  264. }
  265. // This should never happen unless CRiffParser is used incorrectly, in which
  266. // case the assert will help debug. But, in the interest of making Prefix happy...
  267. return E_FAIL;
  268. }
  269. HRESULT CRiffParser::Skip(ULONG ulBytes)
  270. {
  271. assert(m_pChunk);
  272. if (m_pChunk)
  273. {
  274. // Make sure we don't scan beyond the end of the chunk.
  275. if (((long)ulBytes + m_pChunk->lRead) > m_pChunk->cksize)
  276. {
  277. ulBytes -= (ulBytes - (m_pChunk->cksize - m_pChunk->lRead));
  278. }
  279. LARGE_INTEGER li;
  280. li.HighPart = 0;
  281. li.LowPart = ulBytes;
  282. HRESULT hr = m_pStream->Seek( li, STREAM_SEEK_CUR, NULL );
  283. if (SUCCEEDED(hr))
  284. {
  285. m_pChunk->lRead += ulBytes;
  286. }
  287. return hr;
  288. }
  289. // This should never happen unless CRiffParser is used incorrectly, in which
  290. // case the assert will help debug. But, in the interest of making Prefix happy...
  291. return E_FAIL;
  292. }
  293. void CRiffParser::MarkPosition()
  294. {
  295. assert(m_pChunk);
  296. if (m_pChunk)
  297. {
  298. LARGE_INTEGER li;
  299. ULARGE_INTEGER ul;
  300. li.HighPart = 0;
  301. li.LowPart = 0;
  302. m_pStream->Seek(li, STREAM_SEEK_CUR, &ul);
  303. m_pChunk->liPosition.QuadPart = (LONGLONG) ul.QuadPart;
  304. }
  305. }
  306. HRESULT CRiffParser::SeekBack()
  307. {
  308. assert(m_pChunk);
  309. if (m_pChunk)
  310. {
  311. // Move back to the start of the current chunk. Also, store the
  312. // absolute position because that will be useful later when we need to seek to the
  313. // end of this chunk.
  314. ULARGE_INTEGER ul;
  315. LARGE_INTEGER li;
  316. li.QuadPart = 0;
  317. li.QuadPart -= (m_pChunk->lRead + (2 * sizeof(DWORD)));
  318. HRESULT hr = m_pStream->Seek(li, STREAM_SEEK_CUR, &ul);
  319. // Now, save the absolute position for the end of this chunk.
  320. m_pChunk->liPosition.QuadPart = ul.QuadPart +
  321. RIFF_ALIGN(m_pChunk->cksize) + (2 * sizeof(DWORD));
  322. m_pChunk->lRead = 0;
  323. return hr;
  324. }
  325. return E_FAIL;
  326. }
  327. HRESULT CRiffParser::SeekForward()
  328. {
  329. assert(m_pChunk);
  330. if (m_pChunk)
  331. {
  332. m_pChunk->lRead = RIFF_ALIGN(m_pChunk->cksize);
  333. return m_pStream->Seek(m_pChunk->liPosition, STREAM_SEEK_SET, NULL);
  334. }
  335. return E_FAIL;
  336. }