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.

289 lines
8.1 KiB

  1. // --------------------------------------------------------------------------------
  2. // BINDSTM.CPP
  3. // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  4. // Steven J. Bailey
  5. // --------------------------------------------------------------------------------
  6. #include "pch.hxx"
  7. #include "bindstm.h"
  8. #include "demand.h"
  9. #ifdef DEBUG
  10. //#define DEBUG_DUMP_SOURCE
  11. #endif
  12. // --------------------------------------------------------------------------------
  13. // CBindStream::CBindStream
  14. // --------------------------------------------------------------------------------
  15. CBindStream::CBindStream(IStream *pSource) : m_pSource(pSource)
  16. {
  17. Assert(pSource);
  18. m_cRef = 1;
  19. m_pSource->AddRef();
  20. m_dwDstOffset = 0;
  21. m_dwSrcOffset = 0;
  22. #ifdef DEBUG_DUMP_SOURCE
  23. OpenFileStream("c:\\bindsrc.txt", CREATE_ALWAYS, GENERIC_WRITE, &m_pDebug);
  24. #endif
  25. InitializeCriticalSection(&m_cs);
  26. }
  27. // --------------------------------------------------------------------------------
  28. // CBindStream::CBindStream
  29. // --------------------------------------------------------------------------------
  30. CBindStream::~CBindStream(void)
  31. {
  32. #ifdef DEBUG_DUMP_SOURCE
  33. m_pDebug->Commit(STGC_DEFAULT);
  34. m_pDebug->Release();
  35. #endif
  36. SafeRelease(m_pSource);
  37. DeleteCriticalSection(&m_cs);
  38. }
  39. // -------------------------------------------------------------------------
  40. // CBindStream::QueryInterface
  41. // -------------------------------------------------------------------------
  42. STDMETHODIMP CBindStream::QueryInterface(REFIID riid, LPVOID *ppv)
  43. {
  44. // check params
  45. if (ppv == NULL)
  46. return TrapError(E_INVALIDARG);
  47. // Init
  48. *ppv = NULL;
  49. // Find IID
  50. if (IID_IUnknown == riid)
  51. *ppv = (IUnknown *)this;
  52. else if (IID_IStream == riid)
  53. *ppv = (IStream *)this;
  54. else
  55. {
  56. *ppv = NULL;
  57. return TrapError(E_NOINTERFACE);
  58. }
  59. // AddRef It
  60. ((IUnknown *)*ppv)->AddRef();
  61. // Done
  62. return S_OK;
  63. }
  64. // --------------------------------------------------------------------------------
  65. // CBindStream::AddRef
  66. // --------------------------------------------------------------------------------
  67. STDMETHODIMP_(ULONG) CBindStream::AddRef(void)
  68. {
  69. return InterlockedIncrement(&m_cRef);
  70. }
  71. // --------------------------------------------------------------------------------
  72. // CBindStream::AddRef
  73. // --------------------------------------------------------------------------------
  74. STDMETHODIMP_(ULONG) CBindStream::Release(void)
  75. {
  76. LONG cRef = InterlockedDecrement(&m_cRef);
  77. if (0 == cRef)
  78. delete this;
  79. return (ULONG)cRef;
  80. }
  81. #ifdef DEBUG
  82. // --------------------------------------------------------------------------------
  83. // CBindStream::DebugAssertOffset
  84. // --------------------------------------------------------------------------------
  85. void CBindStream::DebugAssertOffset(void)
  86. {
  87. // Locals
  88. DWORD dw;
  89. ULARGE_INTEGER uliSize;
  90. ULARGE_INTEGER uliOffset;
  91. // Validate the size, sizeof m_cDest should always be equal to m_dwSrcOffset
  92. m_cDest.QueryStat(&uliOffset, &uliSize);
  93. // Assert Offset
  94. Assert(uliOffset.HighPart == 0 && m_dwDstOffset == uliOffset.LowPart);
  95. // Assert Size
  96. Assert(uliSize.HighPart == 0 && m_dwSrcOffset == uliSize.LowPart);
  97. }
  98. // --------------------------------------------------------------------------------
  99. // CBindStream::DebugDumpDestStream
  100. // --------------------------------------------------------------------------------
  101. void CBindStream::DebugDumpDestStream(LPCSTR pszFile)
  102. {
  103. // Locals
  104. IStream *pStream;
  105. // Open Stream
  106. if (SUCCEEDED(OpenFileStream((LPSTR)pszFile, CREATE_ALWAYS, GENERIC_WRITE, &pStream)))
  107. {
  108. HrRewindStream(&m_cDest);
  109. HrCopyStream(&m_cDest, pStream, NULL);
  110. pStream->Commit(STGC_DEFAULT);
  111. pStream->Release();
  112. }
  113. else
  114. Assert(FALSE);
  115. // Reset Position of both stream
  116. HrStreamSeekSet(&m_cDest, m_dwDstOffset);
  117. }
  118. #endif // DEBUG
  119. // --------------------------------------------------------------------------------
  120. // CBindStream::Read
  121. // --------------------------------------------------------------------------------
  122. STDMETHODIMP CBindStream::Read(void HUGEP_16 *pv, ULONG cb, ULONG *pcbRead)
  123. {
  124. // Locals
  125. HRESULT hr=S_OK;
  126. HRESULT hrRead=S_OK;
  127. ULONG cbReadDst=0;
  128. ULONG cbReadSrc=0;
  129. ULONG cbGet;
  130. // Invalid Arg
  131. Assert(pv);
  132. // Thread Safety
  133. EnterCriticalSection(&m_cs);
  134. // Destination offset is less than source offset
  135. if (m_dwDstOffset < m_dwSrcOffset)
  136. {
  137. // Compute amount to get
  138. cbGet = min(cb, m_dwSrcOffset - m_dwDstOffset);
  139. // Validate the offsets
  140. #ifdef DEBUG
  141. DebugAssertOffset();
  142. #endif
  143. // Read the amount from the destination
  144. CHECKHR(hr = m_cDest.Read(pv, cbGet, &cbReadDst));
  145. // Increment offset
  146. m_dwDstOffset += cbReadDst;
  147. }
  148. // If we didn't read cb, try to read some more
  149. if (cbReadDst < cb && m_pSource)
  150. {
  151. // Compute amount to get
  152. cbGet = cb - cbReadDst;
  153. // Read the amount from the source
  154. hrRead = m_pSource->Read((LPBYTE)pv + cbReadDst, cbGet, &cbReadSrc);
  155. // Raid-43408: MHTML: images don't load on first load over http, but refresh makes them appear
  156. if (FAILED(hrRead))
  157. {
  158. // If I got an E_PENDING with data read, don't fail yet
  159. if (E_PENDING == hrRead && cbReadSrc > 0)
  160. hrRead = S_OK;
  161. // Otherwise, we really failed, might still be an E_PENDING
  162. else
  163. {
  164. TrapError(hrRead);
  165. goto exit;
  166. }
  167. }
  168. // Debug Dumping
  169. #ifdef DEBUG_DUMP_SOURCE
  170. SideAssert(SUCCEEDED(m_pDebug->Write(pv, cbReadSrc + cbReadDst, NULL)));
  171. #endif
  172. // If we read something
  173. if (cbReadSrc)
  174. {
  175. // Increment source offset
  176. m_dwSrcOffset += cbReadSrc;
  177. // Write to Dest
  178. CHECKHR(hr = m_cDest.Write((LPBYTE)pv + cbReadDst, cbReadSrc, NULL));
  179. // Update Dest offset
  180. m_dwDstOffset += cbReadSrc;
  181. // Validate the offsets
  182. #ifdef DEBUG
  183. DebugAssertOffset();
  184. #endif
  185. }
  186. // Check
  187. Assert(m_dwDstOffset == m_dwSrcOffset);
  188. }
  189. // Return pcbRead
  190. if (pcbRead)
  191. *pcbRead = cbReadDst + cbReadSrc;
  192. exit:
  193. // Thread Safety
  194. LeaveCriticalSection(&m_cs);
  195. // Done
  196. return FAILED(hr) ? hr : hrRead;
  197. }
  198. // --------------------------------------------------------------------------------
  199. // CBindStream::Seek
  200. // --------------------------------------------------------------------------------
  201. STDMETHODIMP CBindStream::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNew)
  202. {
  203. // Locals
  204. HRESULT hr=S_OK;
  205. ULARGE_INTEGER uliOffset;
  206. // Thread Safety
  207. EnterCriticalSection(&m_cs);
  208. // Seek m_cDest
  209. CHECKHR(hr = m_cDest.Seek(dlibMove, dwOrigin, plibNew));
  210. // Get the current offset
  211. m_cDest.QueryStat(&uliOffset, NULL);
  212. // Update m_dwDstOffset
  213. m_dwDstOffset = uliOffset.LowPart;
  214. // Should be less than m_dwSrcOffset
  215. Assert(m_dwDstOffset <= m_dwSrcOffset);
  216. exit:
  217. // Thread Safety
  218. LeaveCriticalSection(&m_cs);
  219. // Done
  220. return hr;
  221. }
  222. // --------------------------------------------------------------------------------
  223. // CBindStream::Stat
  224. // --------------------------------------------------------------------------------
  225. STDMETHODIMP CBindStream::Stat(STATSTG *pStat, DWORD dw)
  226. {
  227. // Invalid Arg
  228. if (NULL == pStat)
  229. return TrapError(E_INVALIDARG);
  230. // As long as we have m_pSource, the size is pending
  231. if (m_pSource)
  232. return TrapError(E_PENDING);
  233. // ZeroInit
  234. ZeroMemory(pStat, sizeof(STATSTG));
  235. // Fill pStat
  236. pStat->type = STGTY_STREAM;
  237. m_cDest.QueryStat(NULL, &pStat->cbSize);
  238. // Done
  239. return S_OK;
  240. }