SimpleStream.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. #pragma once
  2. #ifndef __SimpleStream_h__
  3. #define __SimpleStream_h__
  4. /////////////////////////////////////////////////////////////////////////////
  5. // SimpleStream.h : Declaration of the CTCSimpleStreamImpl class.
  6. /////////////////////////////////////////////////////////////////////////////
  7. // Description: A class that implements an object that supports the IStream
  8. // interface and, therefore, also ISequentialStream. The implementation is
  9. // very simple in that the stream is a fixed size (non-growable), and is
  10. // implemented on a specified pointer.
  11. //
  12. // This object provides an implementation of the IStream interface that is
  13. // imlemented on a fixed, non-growable, memory block.
  14. //
  15. // Note: This implementation does *not* provide any thread synchronization.
  16. // It also does not keep track of any of the time fields. The Stat method
  17. // will always return the current time for all of the time fields.
  18. //
  19. class ATL_NO_VTABLE CTCSimpleStreamImpl :
  20. public IStream,
  21. public CComObjectRoot
  22. {
  23. /////////////////////////////////////////////////////////////////////////////
  24. // Interface Map
  25. public:
  26. BEGIN_COM_MAP(CTCSimpleStreamImpl)
  27. COM_INTERFACE_ENTRY(IStream)
  28. COM_INTERFACE_ENTRY(ISequentialStream)
  29. END_COM_MAP()
  30. /////////////////////////////////////////////////////////////////////////////
  31. // Construction
  32. public:
  33. ///////////////////////////////////////////////////////////////////////////
  34. CTCSimpleStreamImpl() :
  35. m_pbBegin(NULL),
  36. m_pbPosition(NULL),
  37. m_pbEnd(NULL)
  38. {
  39. }
  40. ///////////////////////////////////////////////////////////////////////////
  41. void Init(ULONG cbData, void* pvData)
  42. {
  43. assert(!m_pbBegin && !m_pbPosition && !m_pbEnd);
  44. assert(cbData);
  45. assert(pvData);
  46. assert(!IsBadReadPtr(pvData, cbData));
  47. m_pbBegin = m_pbPosition = reinterpret_cast<BYTE*>(pvData);
  48. m_pbEnd = m_pbBegin + cbData;
  49. }
  50. /////////////////////////////////////////////////////////////////////////////
  51. // ISequentialStream Interface Methods
  52. public:
  53. ///////////////////////////////////////////////////////////////////////////
  54. STDMETHODIMP Read(void* pv, ULONG cb, ULONG* pcbRead)
  55. {
  56. assert(m_pbBegin && m_pbPosition && m_pbEnd);
  57. assert(!IsBadWritePtr(pv, cb));
  58. assert(!pcbRead || !IsBadWritePtr(pcbRead, sizeof(*pcbRead)));
  59. // Compute the number of bytes that can be read
  60. ULONG nMax = m_pbEnd - m_pbPosition;
  61. nMax = min(nMax, cb);
  62. // Copy the maximum number of bytes to the specified buffer
  63. assert(!IsBadReadPtr(m_pbPosition, nMax));
  64. CopyMemory(pv, m_pbPosition, nMax);
  65. // Update the current position
  66. m_pbPosition += nMax;
  67. // Return the number of bytes read, if requested
  68. if (pcbRead)
  69. *pcbRead = nMax;
  70. // Indicate success
  71. return S_OK;
  72. }
  73. ///////////////////////////////////////////////////////////////////////////
  74. STDMETHODIMP Write(const void* pv, ULONG cb, ULONG* pcbWritten)
  75. {
  76. assert(m_pbBegin && m_pbPosition && m_pbEnd);
  77. assert(!IsBadReadPtr(pv, cb));
  78. assert(!pcbWritten || !IsBadWritePtr(pcbWritten, sizeof(*pcbWritten)));
  79. // Compute the number of bytes that can be written
  80. ULONG nMax = m_pbEnd - m_pbPosition;
  81. nMax = min(nMax, cb);
  82. // Copy the maximum number of bytes from the specified buffer
  83. assert(!IsBadWritePtr(m_pbPosition, nMax));
  84. CopyMemory(m_pbPosition, pv, nMax);
  85. // Update the current position
  86. m_pbPosition += nMax;
  87. // Return the number of bytes written, if requested
  88. if (pcbWritten)
  89. *pcbWritten = nMax;
  90. // Indicate success
  91. return S_OK;
  92. }
  93. /////////////////////////////////////////////////////////////////////////////
  94. // IStream Interface Methods
  95. public:
  96. ///////////////////////////////////////////////////////////////////////////
  97. STDMETHODIMP Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin,
  98. ULARGE_INTEGER* plibNewPosition)
  99. {
  100. assert(m_pbBegin && m_pbPosition && m_pbEnd);
  101. assert(!plibNewPosition || !IsBadWritePtr(plibNewPosition,
  102. sizeof(*plibNewPosition)));
  103. // Clear the specified [out] parameter, if not NULL
  104. if (plibNewPosition)
  105. TCZeroMemory(plibNewPosition);
  106. switch (dwOrigin)
  107. {
  108. case STREAM_SEEK_SET:
  109. {
  110. // Validate the position pointer as unsigned and in 32-bit range
  111. if (0 != dlibMove.HighPart)
  112. return STG_E_INVALIDFUNCTION;
  113. // Compute the new position
  114. BYTE* pbNewPosition = m_pbBegin + dlibMove.LowPart;
  115. if (m_pbBegin > pbNewPosition || pbNewPosition > m_pbEnd)
  116. return STG_E_INVALIDFUNCTION;
  117. m_pbPosition = pbNewPosition;
  118. break;
  119. }
  120. case STREAM_SEEK_CUR:
  121. {
  122. // Validate the position pointer as signed and in 32-bit range
  123. if (0 != dlibMove.HighPart && -1 != dlibMove.HighPart)
  124. return STG_E_INVALIDFUNCTION;
  125. // Compute the new position
  126. BYTE* pbNewPosition = m_pbPosition + LONG(dlibMove.LowPart);
  127. if (m_pbBegin > pbNewPosition || pbNewPosition > m_pbEnd)
  128. return STG_E_INVALIDFUNCTION;
  129. m_pbPosition = pbNewPosition;
  130. break;
  131. }
  132. case STREAM_SEEK_END:
  133. {
  134. // Validate the position pointer as signed and in 32-bit range
  135. if (0 != dlibMove.HighPart && -1 != dlibMove.HighPart)
  136. return STG_E_INVALIDFUNCTION;
  137. // Compute the new position
  138. BYTE* pbNewPosition = m_pbEnd + LONG(dlibMove.LowPart);
  139. if (m_pbBegin > pbNewPosition || pbNewPosition > m_pbEnd)
  140. return STG_E_INVALIDFUNCTION;
  141. m_pbPosition = pbNewPosition;
  142. break;
  143. }
  144. default:
  145. return STG_E_INVALIDFUNCTION;
  146. }
  147. // Return the new position, if requested
  148. if (plibNewPosition)
  149. plibNewPosition->LowPart = m_pbPosition - m_pbBegin;
  150. // Indicate success
  151. return S_OK;
  152. }
  153. ///////////////////////////////////////////////////////////////////////////
  154. STDMETHODIMP SetSize(ULARGE_INTEGER libNewSize)
  155. {
  156. assert(m_pbBegin && m_pbPosition && m_pbEnd);
  157. // Validate the specified size as in 32-bit range
  158. if (0 != libNewSize.HighPart)
  159. return STG_E_MEDIUMFULL;
  160. // This stream can only shrink, never grow
  161. if (libNewSize.LowPart > (m_pbEnd - m_pbBegin))
  162. return STG_E_MEDIUMFULL;
  163. // Set the new size of the stream
  164. m_pbEnd = m_pbBegin + libNewSize.LowPart;
  165. m_pbPosition = min(m_pbPosition, m_pbEnd);
  166. // Indicate success
  167. return S_OK;
  168. }
  169. ///////////////////////////////////////////////////////////////////////////
  170. STDMETHODIMP CopyTo(IStream* pstm, ULARGE_INTEGER cb,
  171. ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten)
  172. {
  173. assert(m_pbBegin && m_pbPosition && m_pbEnd);
  174. // Initialize the [out] parameters
  175. if (pcbRead)
  176. TCZeroMemory(pcbRead);
  177. if (pcbWritten)
  178. TCZeroMemory(pcbWritten);
  179. // Ensure that the specified stream pointer is valid
  180. IStreamPtr spstm;
  181. RETURN_FAILED(TCSafeQI(pstm, &spstm));
  182. // Compute the number of bytes that can be copied
  183. ULONG nMax = m_pbEnd - m_pbPosition;
  184. nMax = min(nMax, cb.LowPart);
  185. // Copy from the current seek pointer, the maximum number of bytes
  186. ULONG cbWritten;
  187. RETURN_FAILED(spstm->Write(m_pbPosition, nMax, &cbWritten));
  188. // Update the current position
  189. m_pbPosition += cbWritten;
  190. // Return the number of bytes read, if requested
  191. if (pcbRead)
  192. pcbRead->LowPart = cbWritten;
  193. // Return the number of bytes written, if requested
  194. if (pcbWritten)
  195. pcbWritten->LowPart = cbWritten;
  196. // Indicate success
  197. return S_OK;
  198. }
  199. ///////////////////////////////////////////////////////////////////////////
  200. STDMETHODIMP Commit(DWORD grfCommitFlags)
  201. {
  202. assert(m_pbBegin && m_pbPosition && m_pbEnd);
  203. UNUSED(grfCommitFlags);
  204. return S_OK;
  205. }
  206. ///////////////////////////////////////////////////////////////////////////
  207. STDMETHODIMP Revert(void)
  208. {
  209. assert(m_pbBegin && m_pbPosition && m_pbEnd);
  210. return S_OK;
  211. }
  212. ///////////////////////////////////////////////////////////////////////////
  213. STDMETHODIMP LockRegion(ULARGE_INTEGER libOffset,
  214. ULARGE_INTEGER cb, DWORD dwLockType)
  215. {
  216. assert(m_pbBegin && m_pbPosition && m_pbEnd);
  217. UNUSED(libOffset);
  218. UNUSED(cb);
  219. UNUSED(dwLockType);
  220. return STG_E_INVALIDFUNCTION;
  221. }
  222. ///////////////////////////////////////////////////////////////////////////
  223. STDMETHODIMP UnlockRegion(ULARGE_INTEGER libOffset,
  224. ULARGE_INTEGER cb, DWORD dwLockType)
  225. {
  226. assert(m_pbBegin && m_pbPosition && m_pbEnd);
  227. UNUSED(libOffset);
  228. UNUSED(cb);
  229. UNUSED(dwLockType);
  230. return STG_E_INVALIDFUNCTION;
  231. }
  232. ///////////////////////////////////////////////////////////////////////////
  233. STDMETHODIMP Stat(STATSTG* pstatstg, DWORD grfStatFlag)
  234. {
  235. assert(m_pbBegin && m_pbPosition && m_pbEnd);
  236. UNUSED(grfStatFlag);
  237. // Initialize the specified structures
  238. TCZeroMemory(pstatstg);
  239. // Uset the current time for all time fields
  240. FILETIME ft;
  241. GetSystemTimeAsFileTime(&ft);
  242. // Populate the fields of the specified structure
  243. pstatstg->pwcsName = NULL;
  244. pstatstg->type = STGTY_STREAM;
  245. pstatstg->cbSize.HighPart = 0;
  246. pstatstg->cbSize.LowPart = m_pbEnd - m_pbBegin;
  247. pstatstg->mtime = ft;
  248. pstatstg->ctime = ft;
  249. pstatstg->atime = ft;
  250. pstatstg->grfMode = STGM_READWRITE | STGM_SHARE_DENY_NONE;
  251. pstatstg->grfLocksSupported = 0;
  252. pstatstg->clsid = CLSID_NULL;
  253. // Indicate success
  254. return S_OK;
  255. }
  256. ///////////////////////////////////////////////////////////////////////////
  257. STDMETHODIMP Clone(IStream** ppstm)
  258. {
  259. assert(m_pbBegin && m_pbPosition && m_pbEnd);
  260. // Initialize the [out] parameter
  261. CLEAROUT(ppstm, (IStream*)NULL);
  262. // Do not support this function
  263. return STG_E_INSUFFICIENTMEMORY;
  264. }
  265. /////////////////////////////////////////////////////////////////////////////
  266. // Data Members
  267. protected:
  268. BYTE* m_pbBegin;
  269. BYTE* m_pbEnd;
  270. BYTE* m_pbPosition;
  271. };
  272. /////////////////////////////////////////////////////////////////////////////
  273. // CTCSimpleStream
  274. typedef CComObjectGlobal<CTCSimpleStreamImpl> TCSimpleStream;
  275. /////////////////////////////////////////////////////////////////////////////
  276. #endif // !__SimpleStream_h__