TCNullStreamImpl.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. /////////////////////////////////////////////////////////////////////////////
  2. // TCNullStream.cpp | Implementation of the CTCNullStreamImpl class.<nl><nl>
  3. // This object provides an implementation of the IStream interface that does
  4. // nothing more that count the number of bytes being written to it. Since
  5. // ATL (currently 3.0) implements IPersistStreamInitImpl::GetSizeMax by
  6. // returning E_NOTIMPL, this object can be used in an override of that
  7. // method. This is accomplished by creating an instance of this null stream
  8. // and 'persisting' an object to it, thereby counting the number of bytes
  9. // needed to persist the object without allocating any memory.
  10. //
  11. /////////////////////////////////////////////////////////////////////////////
  12. // CTCNullStreamImpl
  13. #include "TCNullStreamImpl.h"
  14. /////////////////////////////////////////////////////////////////////////////
  15. // Construction
  16. CTCNullStreamImpl::CTCNullStreamImpl() :
  17. m_nPosition(0),
  18. m_nSize(0)
  19. {
  20. // Get the current FILETIME
  21. GetSystemTimeAsFileTime(&m_ftCreated);
  22. m_ftModified = m_ftAccessed = m_ftCreated;
  23. }
  24. /////////////////////////////////////////////////////////////////////////////
  25. // ISequentialStream Interface Methods
  26. STDMETHODIMP CTCNullStreamImpl::Read(void* pv, ULONG cb, ULONG* pcbRead)
  27. {
  28. HRESULT hr = S_OK;
  29. __try
  30. {
  31. // Lock the object
  32. Lock();
  33. // Compute the number of bytes that can be read
  34. ULONG nMax = m_nSize - m_nPosition;
  35. nMax = min(nMax, cb);
  36. // Clear the specified buffer for the maximum number of bytes
  37. ZeroMemory(pv, nMax);
  38. // Update the current position
  39. m_nPosition += nMax;
  40. // Get the current FILETIME
  41. GetSystemTimeAsFileTime(&m_ftAccessed);
  42. // Return the number of bytes read, if requested
  43. if (pcbRead)
  44. *pcbRead = nMax;
  45. }
  46. __except(1)
  47. {
  48. hr = STG_E_INVALIDPOINTER;
  49. }
  50. // Unlock the object
  51. Unlock();
  52. // Return the last result
  53. return hr;
  54. }
  55. STDMETHODIMP CTCNullStreamImpl::Write(const void* pv, ULONG cb,
  56. ULONG* pcbWritten)
  57. {
  58. UNUSED(pv);
  59. HRESULT hr = S_OK;
  60. __try
  61. {
  62. // Lock the object
  63. Lock();
  64. // Increment the current position
  65. m_nPosition += cb;
  66. // Compute the new size
  67. if (m_nPosition > m_nSize)
  68. m_nSize = m_nPosition;
  69. // Get the current FILETIME
  70. GetSystemTimeAsFileTime(&m_ftModified);
  71. // Return the number of bytes written, if requested
  72. if (pcbWritten)
  73. *pcbWritten = cb;
  74. }
  75. __except(1)
  76. {
  77. hr = STG_E_INVALIDPOINTER;
  78. }
  79. // Unlock the object
  80. Unlock();
  81. // Return the last result
  82. return hr;
  83. }
  84. /////////////////////////////////////////////////////////////////////////////
  85. // IStream Interface Methods
  86. STDMETHODIMP CTCNullStreamImpl::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin,
  87. ULARGE_INTEGER* plibNewPosition)
  88. {
  89. // Clear the specified [out] parameter, if not NULL
  90. if (plibNewPosition)
  91. TCZeroMemory(plibNewPosition);
  92. // Lock the object
  93. CLock lock(this);
  94. switch (dwOrigin)
  95. {
  96. case STREAM_SEEK_SET:
  97. {
  98. // Validate the position pointer as unsigned and in 32-bit range
  99. if (0 != dlibMove.HighPart)
  100. return STG_E_INVALIDFUNCTION;
  101. // Compute the new position
  102. m_nPosition = dlibMove.LowPart;
  103. break;
  104. }
  105. case STREAM_SEEK_CUR:
  106. {
  107. // Validate the position pointer as signed and in 32-bit range
  108. if (0 != dlibMove.HighPart && -1 != dlibMove.HighPart)
  109. return STG_E_INVALIDFUNCTION;
  110. // Compute the new position
  111. __int64 nPositionNew = __int64(m_nPosition) + LONG(dlibMove.LowPart);
  112. if (nPositionNew > ULONG_MAX)
  113. return STG_E_MEDIUMFULL;
  114. m_nPosition = ULONG(nPositionNew);
  115. break;
  116. }
  117. case STREAM_SEEK_END:
  118. {
  119. // Validate the position pointer as signed and in 32-bit range
  120. if (0 != dlibMove.HighPart && -1 != dlibMove.HighPart)
  121. return STG_E_INVALIDFUNCTION;
  122. // Compute the new position
  123. __int64 nPositionNew = __int64(m_nSize) + LONG(dlibMove.LowPart);
  124. if (nPositionNew > ULONG_MAX)
  125. return STG_E_MEDIUMFULL;
  126. m_nPosition = ULONG(nPositionNew);
  127. break;
  128. }
  129. default:
  130. return STG_E_INVALIDFUNCTION;
  131. }
  132. // Compute the new size, if position is beyond the end
  133. if (m_nPosition > m_nSize)
  134. m_nSize = m_nPosition;
  135. // Return the new position, if requested
  136. if (plibNewPosition)
  137. plibNewPosition->LowPart = m_nPosition;
  138. // Indicate success
  139. return S_OK;
  140. }
  141. STDMETHODIMP CTCNullStreamImpl::SetSize(ULARGE_INTEGER libNewSize)
  142. {
  143. // Validate the specified size as in 32-bit range
  144. if (0 == libNewSize.HighPart)
  145. return STG_E_INVALIDFUNCTION;
  146. // Lock the object
  147. CLock lock(this);
  148. // Set the new size of the stream
  149. m_nSize = libNewSize.LowPart;
  150. // Indicate success
  151. return S_OK;
  152. }
  153. STDMETHODIMP CTCNullStreamImpl::CopyTo(IStream* pstm, ULARGE_INTEGER cb,
  154. ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten)
  155. {
  156. // Initialize the [out] parameters
  157. if (pcbRead)
  158. TCZeroMemory(pcbRead);
  159. if (pcbWritten)
  160. TCZeroMemory(pcbWritten);
  161. // Ensure that the specified stream pointer is valid
  162. IStreamPtr spstm;
  163. RETURN_FAILED(TCSafeQI(pstm, &spstm));
  164. // Validate the specified size as in 32-bit range
  165. if (0 == cb.HighPart)
  166. return STG_E_INVALIDFUNCTION;
  167. // Initialize a chunk of memory to copy into the specified stream
  168. BYTE pBuf[2048];
  169. const int cbBuf = sizeof(pBuf);
  170. ZeroMemory(pBuf, cbBuf);
  171. // Lock the object
  172. CLock lock(this);
  173. // Compute the number of bytes that can be read
  174. ULONG nMax = m_nSize - m_nPosition;
  175. nMax = min(nMax, cb.LowPart);
  176. // Copy the NULL memory chunk for the specified number of bytes
  177. HRESULT hr;
  178. for (ULONG nRemaining = nMax; nRemaining > cbBuf; nRemaining -= cbBuf)
  179. if (FAILED(hr = spstm->Write(pBuf, cbBuf, NULL)))
  180. return hr;
  181. // Copy any remaining bytes
  182. if (nRemaining && FAILED(hr = spstm->Write(pBuf, nRemaining, NULL)))
  183. return hr;
  184. // Update the current position
  185. m_nPosition += nMax;
  186. // Get the current FILETIME
  187. GetSystemTimeAsFileTime(&m_ftAccessed);
  188. // Return the number of bytes read, if requested
  189. if (pcbRead)
  190. pcbRead->LowPart = nMax;
  191. // Return the number of bytes written, if requested
  192. if (pcbWritten)
  193. pcbWritten->LowPart = nMax;
  194. // Indicate success
  195. return S_OK;
  196. }
  197. STDMETHODIMP CTCNullStreamImpl::Commit(DWORD grfCommitFlags)
  198. {
  199. UNUSED(grfCommitFlags);
  200. return E_NOTIMPL;
  201. }
  202. STDMETHODIMP CTCNullStreamImpl::Revert(void)
  203. {
  204. return E_NOTIMPL;
  205. }
  206. STDMETHODIMP CTCNullStreamImpl::LockRegion(ULARGE_INTEGER libOffset,
  207. ULARGE_INTEGER cb, DWORD dwLockType)
  208. {
  209. UNUSED(libOffset);
  210. UNUSED(cb);
  211. UNUSED(dwLockType);
  212. return E_NOTIMPL;
  213. }
  214. STDMETHODIMP CTCNullStreamImpl::UnlockRegion(ULARGE_INTEGER libOffset,
  215. ULARGE_INTEGER cb, DWORD dwLockType)
  216. {
  217. UNUSED(libOffset);
  218. UNUSED(cb);
  219. UNUSED(dwLockType);
  220. return E_NOTIMPL;
  221. }
  222. STDMETHODIMP CTCNullStreamImpl::Stat(STATSTG* pstatstg, DWORD grfStatFlag)
  223. {
  224. UNUSED(grfStatFlag);
  225. // Initialize the specified structures
  226. TCZeroMemory(pstatstg);
  227. // Lock the object
  228. CLock lock(this);
  229. // Populate the fields of the specified structure
  230. pstatstg->pwcsName = NULL;
  231. pstatstg->type = STGTY_STREAM;
  232. pstatstg->cbSize.HighPart = 0;
  233. pstatstg->cbSize.LowPart = m_nSize;
  234. pstatstg->mtime = m_ftModified;
  235. pstatstg->ctime = m_ftCreated;
  236. pstatstg->atime = m_ftAccessed;
  237. pstatstg->grfMode = STGM_READWRITE | STGM_SHARE_DENY_NONE;
  238. pstatstg->grfLocksSupported = 0;
  239. pstatstg->clsid = CLSID_NULL;
  240. // Indicate success
  241. return S_OK;
  242. }
  243. STDMETHODIMP CTCNullStreamImpl::Clone(IStream** ppstm)
  244. {
  245. // Initialize the [out] parameter
  246. CLEAROUT(ppstm, (IStream*)NULL);
  247. // Create an new instance of ourself
  248. typedef CComObject<CTCNullStreamImpl> CNullStreamObject;
  249. CNullStreamObject* pObject = NULL;
  250. HRESULT hr = CNullStreamObject::CreateInstance(&pObject);
  251. RETURN_FAILED(hr);
  252. // The QueryInterface will put a refcount of 1 on the new object
  253. IStreamPtr pstm(pObject->GetUnknown());
  254. // Lock the object
  255. CLock lock(this);
  256. // Initialize the new stream with our seek pointer and size
  257. LARGE_INTEGER dlibMove = {0, m_nPosition};
  258. ULARGE_INTEGER libNewSize = {0, m_nSize};
  259. _SVERIFY(hr = pstm->Seek(dlibMove, STREAM_SEEK_SET, NULL));
  260. _SVERIFY(hr = pstm->SetSize(libNewSize));
  261. // Detach the new stream to the specified [out] parameter
  262. *ppstm = pstm;
  263. pstm.Detach();
  264. // Indicate success
  265. return S_OK;
  266. }