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.

1280 lines
32 KiB

  1. #ifndef _ASTREAM_H_
  2. #define _ASTREAM_H_
  3. // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  4. //
  5. // ASTREAM.H
  6. //
  7. // Async streams header.
  8. //
  9. #include <ex\refcnt.h>
  10. #include <ex\refhandle.h>
  11. // ========================================================================
  12. //
  13. // CLASS IAsyncReadObserver
  14. //
  15. // Passed to IAsyncStream::AsyncRead() and called when the asynchronous
  16. // operation completes.
  17. //
  18. class IAsyncReadObserver
  19. {
  20. // NOT IMPLEMENTED
  21. //
  22. IAsyncReadObserver& operator=( const IAsyncReadObserver& );
  23. public:
  24. // CREATORS
  25. //
  26. virtual ~IAsyncReadObserver() = 0 {}
  27. // MANIPULATORS
  28. //
  29. virtual VOID ReadComplete( UINT cbRead, HRESULT hr ) = 0;
  30. };
  31. // ========================================================================
  32. //
  33. // CLASS IAsyncWriteObserver
  34. //
  35. // Passed to IAsyncStream::AsyncWrite() and called when the asynchronous
  36. // operation completes.
  37. //
  38. class IAsyncWriteObserver : public IRefCounted
  39. {
  40. // NOT IMPLEMENTED
  41. //
  42. IAsyncWriteObserver& operator=( const IAsyncWriteObserver& );
  43. public:
  44. // CREATORS
  45. //
  46. virtual ~IAsyncWriteObserver() = 0 {}
  47. // MANIPULATORS
  48. //
  49. virtual VOID WriteComplete( UINT cbWritten, HRESULT hr ) = 0;
  50. };
  51. // ========================================================================
  52. //
  53. // CLASS IAsyncFlushObserver
  54. //
  55. // Passed to IAsyncStream::AsyncFlush() and called when the asynchronous
  56. // operation completes.
  57. //
  58. class IAsyncFlushObserver : public IRefCounted
  59. {
  60. // NOT IMPLEMENTED
  61. //
  62. IAsyncFlushObserver& operator=( const IAsyncFlushObserver& );
  63. public:
  64. // CREATORS
  65. //
  66. virtual ~IAsyncFlushObserver() = 0 {}
  67. // MANIPULATORS
  68. //
  69. virtual VOID FlushComplete( HRESULT hr ) = 0;
  70. };
  71. // ========================================================================
  72. //
  73. // CLASS IAsyncCopyToObserver
  74. //
  75. // Passed to IAsyncStream::AsyncCopyTo() and called when the asynchronous
  76. // operation completes.
  77. //
  78. class IAsyncCopyToObserver
  79. {
  80. // NOT IMPLEMENTED
  81. //
  82. IAsyncCopyToObserver& operator=( const IAsyncCopyToObserver& );
  83. public:
  84. // CREATORS
  85. //
  86. virtual ~IAsyncCopyToObserver() = 0 {}
  87. // MANIPULATORS
  88. //
  89. virtual VOID CopyToComplete( UINT cbCopied, HRESULT hr ) = 0;
  90. };
  91. // ========================================================================
  92. //
  93. // CLASS IDavStream
  94. //
  95. // Interface for sync streams.
  96. //
  97. class IDavStream
  98. {
  99. // NOT IMPLEMENTED
  100. //
  101. IDavStream& operator=( const IDavStream& );
  102. protected:
  103. // CREATORS
  104. //
  105. // Only create this object through it's descendents!
  106. //
  107. IDavStream() {};
  108. public:
  109. // DESTRUCTORS
  110. //
  111. // Out of line virtual destructor necessary for proper
  112. // deletion of objects of derived classes via this class
  113. //
  114. virtual ~IDavStream() = 0
  115. {
  116. }
  117. // ACCESSORS
  118. //
  119. // DwLeft() is the function that must be implemented by the descendants of this
  120. // interface if they are to be passed to
  121. //
  122. // IHybridStream::ScCopyFrom(const IDavStream * stmSrc,
  123. // IAsyncWriteObserver * pobsAsyncWrite)
  124. //
  125. // In that case it must return the number of bytes left in the stream to drain.
  126. // That size can be an estimated one, not necessarily exact. That has to be
  127. // implemented, that way, as the stream size that we are getting from the store
  128. // when we open the stream on the property may be not correct (from the
  129. // experience in that I can tell that still in most cases that data is
  130. // correct, except for PR_BODY). Also for example in conversion streams we will
  131. // not know the stream size in advance (we have not read all data yet and do not
  132. // know in what converted size it will result in). Descendants that are not intended to
  133. // be passed to the call above may choose to implement DwLeft() to trap or return 0.
  134. // Of course in that case they should not rely on information comming back from
  135. // that call. Also as soon as it is finally determined that we have reached the
  136. // end of the stream (i.e. we read a piece of data, and we read less than we asked for),
  137. // the function should always return 0.
  138. //
  139. virtual DWORD DwLeft() const = 0;
  140. // FEnd() is the function that must return TRUE in the case the whole stream has been
  141. // already drained/consumed. FALSE must be returned in all other cases. Child classes
  142. // may implement it to return FALSE always if they are always sure that ScCopyFrom
  143. // operations from this stream will always be given amount of bytes to copy that is
  144. // equal or less than actual amount of bytes still remaining in the stream. Of course
  145. // if they choose always to return FLASE they should not use the function to determine
  146. // if they reached the end of the stream.
  147. //
  148. virtual BOOL FEnd() const
  149. {
  150. TrapSz("IDavStream::FEnd() not implemented");
  151. return FALSE;
  152. }
  153. // ScRead() reading from the stream
  154. //
  155. virtual SCODE ScRead( BYTE * pbBuf,
  156. UINT cbToRead,
  157. UINT * pcbRead ) const
  158. {
  159. TrapSz("IDavStream::ScRead() not implemented");
  160. return E_NOTIMPL;
  161. }
  162. // MANIPULATORS
  163. //
  164. virtual SCODE ScWrite( const BYTE * pbBuf,
  165. UINT cbToWrite,
  166. UINT * pcbWritten )
  167. {
  168. TrapSz("IDavStream::ScWrite() not implemented");
  169. return E_NOTIMPL;
  170. }
  171. virtual SCODE ScCopyTo( IDavStream& stmDst,
  172. UINT cbToCopy,
  173. UINT * pcbCopied )
  174. {
  175. TrapSz("IDavStream::ScCopyTo() not implemented");
  176. return E_NOTIMPL;
  177. }
  178. virtual SCODE ScFlush()
  179. {
  180. return S_OK;
  181. }
  182. };
  183. // ========================================================================
  184. //
  185. // CLASS IAsyncStream
  186. //
  187. // Interface for async streams.
  188. //
  189. // AsyncRead() -
  190. // Asynchronously reads bytes from a stream and notifies an
  191. // observer when the I/O completes. IAsyncStream provides
  192. // a default implementation that notifies the observer with
  193. // 0 bytes read and an HRESULT of E_NOTIMPL.
  194. //
  195. // AsyncWrite()
  196. // Asynchronously writes bytes to a stream and notifies an
  197. // observer when the I/O completes. IAsyncStream provides
  198. // a default implementation that notifies the observer with
  199. // 0 bytes written and an HRESULT of E_NOTIMPL.
  200. //
  201. // AsyncCopyTo()
  202. // Asynchronously copies bytes from this stream to another
  203. // IAsyncStream and notifies an observer when the I/O completes.
  204. // IAsyncStream provides a default implementation that notifies
  205. // the observer with 0 bytes copied and an HRESULT of E_NOTIMPL.
  206. //
  207. // AsyncFlush()
  208. // To be used with buffered writable streams. Asynchronously
  209. // flushes accumulated data written in previous calls to
  210. // AsyncWrite() and notifies an observer when the I/O completes.
  211. // IAsyncStream provides a default implementation that notifies
  212. // the observer with an HRESULT of E_NOTIMPL.
  213. //
  214. // !!!IMPORTANT!!!
  215. // Despite the refcounted base class of IAsyncWriteObserver and IAsyncFlushObserver,
  216. // it is the CALLER's sole responsbility to guarantee the lifetime of the stream
  217. // and observers through completion of any async I/O call.
  218. //
  219. class IAsyncStream
  220. {
  221. // NOT IMPLEMENTED
  222. //
  223. IAsyncStream& operator=( const IAsyncStream& );
  224. public:
  225. // DESTRUCTORS
  226. //
  227. virtual ~IAsyncStream() = 0
  228. {
  229. }
  230. // ACCESSORS
  231. //
  232. virtual UINT CbReady() const
  233. {
  234. return 0;
  235. }
  236. // MANIPULATORS
  237. //
  238. virtual VOID AsyncRead( BYTE * pbBuf,
  239. UINT cbToRead,
  240. IAsyncReadObserver& obsAsyncRead )
  241. {
  242. obsAsyncRead.ReadComplete( 0, E_NOTIMPL );
  243. }
  244. virtual VOID AsyncWrite( const BYTE * pbBuf,
  245. UINT cbToWrite,
  246. IAsyncWriteObserver& obsAsyncWrite )
  247. {
  248. obsAsyncWrite.WriteComplete( 0, E_NOTIMPL );
  249. }
  250. virtual VOID AsyncCopyTo( IAsyncStream& stmDst,
  251. UINT cbToCopy,
  252. IAsyncCopyToObserver& obsAsyncCopyTo )
  253. {
  254. obsAsyncCopyTo.CopyToComplete( 0, E_NOTIMPL );
  255. }
  256. virtual VOID AsyncFlush( IAsyncFlushObserver& obsAsyncFlush )
  257. {
  258. obsAsyncFlush.FlushComplete( E_NOTIMPL );
  259. }
  260. };
  261. // ========================================================================
  262. //
  263. // CLASS IHybridStream
  264. //
  265. // Interface for a hybrid sync/async stream. The main difference
  266. // between this interface and IAsyncStream is that the calls here
  267. // do not always complete via async observer notification. If a
  268. // call executes synchronously, it fills in all return values and
  269. // returns status via an SCODE. If a call executes asynchronously,
  270. // it immediately returns E_PENDING and calls the completion observer
  271. // with return values and status when the asynchronous I/O completes.
  272. //
  273. // Callers cannot control whether a call executes synchronously or
  274. // asynchronously.
  275. //
  276. // !!!IMPORTANT!!!
  277. // Despite the refcounted base class of IAsyncWriteObserver and IAsyncFlushObserver,
  278. // it is the CALLER's sole responsbility to guarantee the lifetime of the stream
  279. // and observers through completion of any async I/O call.
  280. //
  281. class IHybridStream
  282. {
  283. // NOT IMPLEMENTED
  284. //
  285. IHybridStream& operator=( const IHybridStream& );
  286. public:
  287. // CREATORS
  288. //
  289. virtual ~IHybridStream() = 0
  290. {
  291. }
  292. // ACCESSORS
  293. //
  294. virtual UINT CbSize() const
  295. {
  296. TrapSz("IHybridStream::CbSize() not implemented");
  297. return 0;
  298. }
  299. // MANIPULATORS
  300. //
  301. virtual SCODE ScRead( BYTE * pbToRead,
  302. DWORD cbToRead,
  303. DWORD * pcbRead,
  304. IAsyncReadObserver * pobsAsyncRead )
  305. {
  306. TrapSz("IHybridStream::ScRead() not implemented");
  307. return E_NOTIMPL;
  308. }
  309. virtual SCODE ScWrite( const BYTE * pbToWrite,
  310. DWORD cbToWrite,
  311. DWORD * pcbWritten,
  312. IAsyncWriteObserver * pobsAsyncWrite )
  313. {
  314. TrapSz("IHybridStream::ScWrite() not implemented");
  315. return E_NOTIMPL;
  316. }
  317. virtual SCODE ScCopyFrom( const IDavStream * pdsToCopy,
  318. const DWORD cbToCopy,
  319. DWORD * pcbCopied,
  320. IAsyncWriteObserver * pobsAsyncWrite )
  321. {
  322. TrapSz("IHybridStream::ScCopyFrom() not implemented");
  323. return E_NOTIMPL;
  324. }
  325. virtual SCODE ScCopyFrom( const IDavStream * pdsToCopy,
  326. IAsyncWriteObserver * pobsAsyncWrite )
  327. {
  328. DWORD cbCopied;
  329. return ScCopyFrom( pdsToCopy,
  330. pdsToCopy->DwLeft(),
  331. &cbCopied,
  332. pobsAsyncWrite);
  333. }
  334. virtual SCODE ScCopyTo( IHybridStream& stmDst,
  335. DWORD cbToCopy,
  336. DWORD * pcbCopied,
  337. IAsyncCopyToObserver * pobsAsyncCopyTo )
  338. {
  339. TrapSz("IHybridStream::ScCopyTo() not implemented");
  340. return E_NOTIMPL;
  341. }
  342. virtual SCODE ScFlush( IAsyncFlushObserver * pobsAsyncFlush )
  343. {
  344. TrapSz("IHybridStream::ScFlush() not implemented");
  345. return E_NOTIMPL;
  346. }
  347. };
  348. // ========================================================================
  349. //
  350. // TEMPLATE CLASS CBufferedStream
  351. //
  352. // Inline buffering stream implementation. See !!! IMPORTANT !!! section
  353. // below for limitations and other considerations.
  354. //
  355. // Template parameters:
  356. //
  357. // _RawStream
  358. // Raw stream type. _RawStream must implement ScReadRaw() for
  359. // CBufferedStream::ScRead(), if it is to be used, and ScWriteRaw()
  360. // for CBufferedStream::ScWrite() and CBufferedStream::ScFlush()
  361. // if they are to be used. The prototypes are:
  362. //
  363. // SCODE ScReadRaw( BYTE * pbToRead,
  364. // DWORD cbToRead,
  365. // DWORD * pcbRead,
  366. // IAsyncReadObserver * pobsAsyncRead );
  367. //
  368. // SCODE ScWriteRaw( const BYTE * pbToWrite,
  369. // DWORD cbToWrite,
  370. // DWORD * pcbWritten,
  371. // IAsyncWriteObserver * pobsAsyncWrite );
  372. //
  373. // These functions read and write from the raw stream. The I/O
  374. // they implement can be synchronous or asynchronous or both.
  375. //
  376. // CB_BUF
  377. // Size (in bytes) of the buffer to use. The buffer is a direct
  378. // member of CBufferedStream; no allocation is done.
  379. //
  380. //
  381. // !!! IMPORTANT !!!
  382. //
  383. // Reading and writing:
  384. // There is no restriction on the amount of data that can be read
  385. // or written at once, but data is buffered CB_BUF bytes at a time.
  386. // This means that a request to write, for example, 128K of data
  387. // will incur two buffer flushes when CB_BUF is 64K. The same
  388. // is true of reads and buffer fills. Buffer flushes/fills are
  389. // typically the expensive I/O operations, so choose a CB_BUF
  390. // that works well with the particular I/O (e.g. 64K for file I/O).
  391. //
  392. // Flushing:
  393. // There is an assumption in ScFlush() that the stream being flushed
  394. // to is not a buffered stream; ScFlush() does not flush the raw stream.
  395. //
  396. // Class size:
  397. // Since the buffer is inline (i.e. not allocated), instances of this class
  398. // can potentially be large. Whenever such an instance is used as a
  399. // direct member of another class, it should be the last such member so as
  400. // to maximize data locality when accessing other members of the class.
  401. //
  402. template<class _RawStream, UINT CB_BUF>
  403. class CBufferedStream :
  404. private IAsyncReadObserver,
  405. private IAsyncWriteObserver
  406. {
  407. // Amount of the buffer used.
  408. //
  409. UINT m_cbBufUsed;
  410. // Index of next byte to read from buffer.
  411. //
  412. UINT m_ibBufCur;
  413. // Per read/write request state. These members are used
  414. // to keep track of state across various async I/O calls.
  415. //
  416. const IDavStream * m_pdsRequest;
  417. LPBYTE m_pbRequest;
  418. DWORD m_cbRequest;
  419. DWORD m_cbRequestDone;
  420. // Caller-supplied observers. Used to notify the caller
  421. // when I/O completes.
  422. //
  423. IAsyncReadObserver * m_pobsRead;
  424. IAsyncWriteObserver * m_pobsWrite;
  425. IAsyncFlushObserver * m_pobsFlush;
  426. // Pointer to the raw stream. Used in buffer filling/flushing.
  427. //
  428. _RawStream * m_pstmRaw;
  429. // The buffer. The CB_BUF size is a template parameter.
  430. //
  431. BYTE m_rgbBuf[CB_BUF];
  432. // Internal I/O routines
  433. //
  434. inline SCODE ScReadInt();
  435. inline SCODE ScWriteInt();
  436. inline SCODE ScCopyFromInt();
  437. // Raw stream I/O completion routines
  438. //
  439. inline VOID RawReadComplete(UINT cbReadRaw);
  440. inline VOID RawWriteComplete(UINT cbWrittenRaw);
  441. // Buffer filling and flushing utilities
  442. //
  443. inline SCODE ScFillBuffer();
  444. inline SCODE ScFlushBuffer();
  445. // NOT IMPLEMENTED
  446. //
  447. CBufferedStream( const CBufferedStream& );
  448. CBufferedStream& operator=( const CBufferedStream& );
  449. public:
  450. // CREATORS
  451. //
  452. CBufferedStream() :
  453. m_cbBufUsed(0),
  454. m_ibBufCur(0),
  455. m_pobsRead(NULL),
  456. m_pobsWrite(NULL),
  457. m_pobsFlush(NULL)
  458. {
  459. }
  460. // ACCESSORS
  461. //
  462. ULONG CbBufUsed() const
  463. {
  464. return m_cbBufUsed;
  465. }
  466. // MANIPULATORS
  467. //
  468. inline
  469. SCODE ScRead( _RawStream& stmRaw,
  470. BYTE * pbToRead,
  471. DWORD cbToRead,
  472. DWORD * pcbRead,
  473. IAsyncReadObserver * pobsReadExt );
  474. inline
  475. SCODE ScWrite( _RawStream& stmRaw,
  476. const BYTE * pbToWrite,
  477. DWORD cbToWrite,
  478. DWORD * pcbWritten,
  479. IAsyncWriteObserver * pobsWriteExt );
  480. inline
  481. SCODE ScCopyFrom( _RawStream& stmRaw,
  482. const IDavStream * pdsToCopy,
  483. const DWORD cbToCopy,
  484. DWORD * pcbCopied,
  485. IAsyncWriteObserver * pobsWriteExt );
  486. inline
  487. SCODE ScFlush( _RawStream& stmRaw,
  488. IAsyncFlushObserver * pobsFlushExt );
  489. // IAsyncReadObserver/IAsyncWriteObserver
  490. //
  491. // Note: these functions are not really inlined -- they are declared
  492. // virtual in the observer interface classes. However we must declare
  493. // them inline so that the compiler will generate one instance of each
  494. // function rather than one instance per function per module. This is
  495. // the member function equivalent of DEC_CONST.
  496. //
  497. inline
  498. VOID ReadComplete( UINT cbReadRaw,
  499. HRESULT hr );
  500. inline
  501. VOID WriteComplete( UINT cbWrittenRaw,
  502. HRESULT hr );
  503. //$REVIEW
  504. //
  505. // IAsyncWriteObserver and IAsyncReadObserver are both refcounted
  506. // interfaces and don't need to be. Caller assumes all responsibility
  507. // for keeping stream and observer objects alive through any stream
  508. // call.
  509. //
  510. void AddRef()
  511. {
  512. TrapSz("CBufferedStream::AddRef() is not implemented!");
  513. }
  514. void Release()
  515. {
  516. TrapSz("CBufferedStream::Release() is not implemented!");
  517. }
  518. };
  519. template<class _RawStream, UINT CB_BUF>
  520. SCODE
  521. CBufferedStream<_RawStream, CB_BUF>::ScRead(
  522. _RawStream& stmRaw,
  523. BYTE * pbToRead,
  524. DWORD cbToRead,
  525. DWORD * pcbRead,
  526. IAsyncReadObserver * pobsReadExt )
  527. {
  528. // Check parameters
  529. //
  530. Assert(cbToRead > 0);
  531. Assert(!IsBadWritePtr(pbToRead, cbToRead));
  532. Assert(!IsBadWritePtr(pcbRead, sizeof(UINT)));
  533. Assert(!pobsReadExt || !IsBadReadPtr(pobsReadExt, sizeof(IAsyncReadObserver)));
  534. // We had better not be in any I/O of any sort.
  535. //
  536. Assert(!m_pobsRead);
  537. Assert(!m_pobsWrite);
  538. Assert(!m_pobsFlush);
  539. // Set up state for a new read
  540. //
  541. m_pstmRaw = &stmRaw;
  542. m_pdsRequest = NULL;
  543. m_pbRequest = pbToRead;
  544. m_cbRequest = cbToRead;
  545. m_pobsRead = pobsReadExt;
  546. m_cbRequestDone = 0;
  547. // Issue the read
  548. //
  549. SCODE sc = ScReadInt();
  550. // If the read didn't pend then clear out the observer
  551. // and return the amount of data read.
  552. //
  553. if (E_PENDING != sc)
  554. {
  555. m_pobsRead = NULL;
  556. *pcbRead = m_cbRequestDone;
  557. }
  558. // Return the result of the I/O, which may be S_OK, E_PENDING
  559. // or any other error.
  560. //
  561. return sc;
  562. }
  563. template<class _RawStream, UINT CB_BUF>
  564. SCODE
  565. CBufferedStream<_RawStream, CB_BUF>::ScReadInt()
  566. {
  567. SCODE sc = S_OK;
  568. // Loop around alternately filling and reading from the
  569. // buffer until we finish the request or until a fill pends.
  570. //
  571. while ( m_cbRequestDone < m_cbRequest )
  572. {
  573. // If we have read everything from the buffer then try
  574. // to refill the buffer from the raw stream.
  575. //
  576. if (m_ibBufCur == m_cbBufUsed)
  577. {
  578. sc = ScFillBuffer();
  579. if (FAILED(sc))
  580. {
  581. if (E_PENDING != sc)
  582. DebugTrace("CBufferedStream::ScReadInt() - ScFillBuffer() failed 0x%08lX\n", sc);
  583. break;
  584. }
  585. // If the buffer is still empty then we have
  586. // exhausted the stream, so we are done.
  587. //
  588. if (0 == m_cbBufUsed)
  589. break;
  590. }
  591. // The buffer should have data available to be read
  592. // so read it.
  593. //
  594. Assert(m_ibBufCur < m_cbBufUsed);
  595. DWORD cbToRead = min(m_cbBufUsed - m_ibBufCur,
  596. m_cbRequest - m_cbRequestDone);
  597. memcpy(m_pbRequest + m_cbRequestDone,
  598. &m_rgbBuf[m_ibBufCur],
  599. cbToRead);
  600. m_ibBufCur += cbToRead;
  601. m_cbRequestDone += cbToRead;
  602. }
  603. return sc;
  604. }
  605. template<class _RawStream, UINT CB_BUF>
  606. SCODE
  607. CBufferedStream<_RawStream, CB_BUF>::ScFillBuffer()
  608. {
  609. // We better have a stream to fill from
  610. //
  611. Assert(m_pstmRaw);
  612. // Assert that we are not in any write/copy/flush I/O
  613. //
  614. Assert(!m_pobsWrite);
  615. Assert(!m_pobsFlush);
  616. // We should only try to refill the buffer after all
  617. // of the data in it has been consumed.
  618. //
  619. Assert(m_ibBufCur == m_cbBufUsed);
  620. // Reset the buffer back to the beginning.
  621. //
  622. m_cbBufUsed = 0;
  623. m_ibBufCur = 0;
  624. // Read data in from the raw stream. If reading pends on I/O
  625. // then we will resume processing in CBufferedStream::ReadComplete()
  626. // when the I/O completes.
  627. //
  628. DWORD cbRead = 0;
  629. SCODE sc = m_pstmRaw->ScReadRaw(m_rgbBuf,
  630. CB_BUF,
  631. &cbRead,
  632. this);
  633. if (SUCCEEDED(sc))
  634. {
  635. // ScReadRaw() did not pend, so update our internal state and continue.
  636. //
  637. RawReadComplete(cbRead);
  638. }
  639. else if (E_PENDING != sc)
  640. {
  641. DebugTrace("CBufferedStream::ScFillBuffer() - m_pstmRaw->ScReadRaw() failed 0x%08lX\n", sc);
  642. }
  643. return sc;
  644. }
  645. template<class _RawStream, UINT CB_BUF>
  646. VOID
  647. CBufferedStream<_RawStream, CB_BUF>::ReadComplete( UINT cbReadRaw,
  648. HRESULT hr )
  649. {
  650. // Update our internal state
  651. //
  652. RawReadComplete(cbReadRaw);
  653. // If I/O succeeded then continue reading where we left off.
  654. // We are done reading only when ScReadInt() returns S_OK
  655. // or any error other than E_PENDING.
  656. //
  657. if (SUCCEEDED(hr))
  658. {
  659. hr = ScReadInt();
  660. if (E_PENDING == hr)
  661. return;
  662. if (FAILED(hr))
  663. DebugTrace("CBufferedStream::ReadComplete() - ScReadInt() failed 0x%08lX\n", hr);
  664. }
  665. // Pull the external read observer from where we saved it
  666. //
  667. Assert(m_pobsRead);
  668. IAsyncReadObserver * pobsReadExt = m_pobsRead;
  669. m_pobsRead = NULL;
  670. // Complete the read by calling the client back with
  671. // total amount read for the request.
  672. //
  673. // Note that m_cbRequestDone != m_cbRequest only when there
  674. // is an error.
  675. //
  676. Assert(FAILED(hr) || m_cbRequestDone == m_cbRequest);
  677. pobsReadExt->ReadComplete(m_cbRequestDone, hr);
  678. }
  679. template<class _RawStream, UINT CB_BUF>
  680. VOID
  681. CBufferedStream<_RawStream, CB_BUF>::RawReadComplete(UINT cbReadRaw)
  682. {
  683. Assert(0 == m_cbBufUsed);
  684. Assert(0 == m_ibBufCur);
  685. // Update the number of bytes read
  686. //
  687. m_cbBufUsed = cbReadRaw;
  688. }
  689. template<class _RawStream, UINT CB_BUF>
  690. SCODE
  691. CBufferedStream<_RawStream, CB_BUF>::ScWrite(
  692. _RawStream& stmRaw,
  693. const BYTE * pbToWrite,
  694. DWORD cbToWrite,
  695. DWORD * pcbWritten,
  696. IAsyncWriteObserver * pobsWriteExt )
  697. {
  698. // Check parameters
  699. //
  700. Assert(cbToWrite > 0);
  701. Assert(!IsBadReadPtr(pbToWrite, cbToWrite));
  702. Assert(!IsBadWritePtr(pcbWritten, sizeof(UINT)));
  703. Assert(!pobsWriteExt || !IsBadReadPtr(pobsWriteExt, sizeof(IAsyncWriteObserver)));
  704. // We had better not be in any I/O of any sort.
  705. //
  706. Assert(!m_pobsRead);
  707. Assert(!m_pobsWrite);
  708. Assert(!m_pobsFlush);
  709. // Set up state for a new write. Casting away const-ness is OK;
  710. // we don't write to m_pbRequest on writes.
  711. //
  712. m_pstmRaw = &stmRaw;
  713. m_pdsRequest = NULL;
  714. m_pbRequest = const_cast<BYTE *>(pbToWrite);
  715. m_cbRequest = cbToWrite;
  716. m_pobsWrite = pobsWriteExt;
  717. m_cbRequestDone = 0;
  718. // Issue the write
  719. //
  720. SCODE sc = ScWriteInt();
  721. // If the write didn't pend then clear out the observer
  722. // and return the amount of data written.
  723. //
  724. if (E_PENDING != sc)
  725. {
  726. m_pobsWrite = NULL;
  727. *pcbWritten = m_cbRequestDone;
  728. }
  729. // Return the result of the I/O, which may be S_OK, E_PENDING
  730. // or any other error.
  731. //
  732. return sc;
  733. }
  734. template<class _RawStream, UINT CB_BUF>
  735. SCODE
  736. CBufferedStream<_RawStream, CB_BUF>::ScCopyFrom(
  737. _RawStream& stmRaw,
  738. const IDavStream * pdsToCopy,
  739. const DWORD cbToCopy,
  740. DWORD * pcbCopied,
  741. IAsyncWriteObserver * pobsWriteExt )
  742. {
  743. // Check parameters
  744. //
  745. Assert(cbToCopy >= 0);
  746. Assert(!IsBadReadPtr(pdsToCopy, sizeof(IDavStream)));
  747. Assert(!IsBadWritePtr(pcbCopied, sizeof(UINT)));
  748. Assert(!pobsWriteExt || !IsBadReadPtr(pobsWriteExt, sizeof(IAsyncWriteObserver)));
  749. // We had better not be in any I/O of any sort.
  750. //
  751. Assert(!m_pobsRead);
  752. Assert(!m_pobsWrite);
  753. Assert(!m_pobsFlush);
  754. // Set up state for a new write. Casting away const-ness is OK;
  755. // we don't write to m_pbRequest on writes.
  756. //
  757. m_pstmRaw = &stmRaw;
  758. m_pdsRequest = pdsToCopy;
  759. m_pbRequest = NULL;
  760. m_cbRequest = cbToCopy;
  761. m_pobsWrite = pobsWriteExt;
  762. m_cbRequestDone = 0;
  763. // Issue the write
  764. //
  765. SCODE sc = ScCopyFromInt();
  766. // If the write didn't pend then clear out the observer
  767. // and return the amount of data written.
  768. //
  769. if (E_PENDING != sc)
  770. {
  771. m_pobsWrite = NULL;
  772. *pcbCopied = m_cbRequestDone;
  773. }
  774. // Return the result of the I/O, which may be S_OK, E_PENDING
  775. // or any other error.
  776. //
  777. return sc;
  778. }
  779. template<class _RawStream, UINT CB_BUF>
  780. SCODE
  781. CBufferedStream<_RawStream, CB_BUF>::ScWriteInt()
  782. {
  783. SCODE sc = S_OK;
  784. // Loop around alternately filling and flushing the buffer until
  785. // we finish the request or until a buffer flush pends.
  786. //
  787. while ( m_cbRequestDone < m_cbRequest )
  788. {
  789. // If there is no room left to write to the buffer then flush
  790. // the buffer to the raw stream.
  791. //
  792. if (CB_BUF == m_cbBufUsed)
  793. {
  794. sc = ScFlushBuffer();
  795. if (FAILED(sc))
  796. {
  797. if (E_PENDING != sc)
  798. DebugTrace("CBufferedStream::ScWriteInt() - ScFlushBuffer() failed 0x%08lX\n", sc);
  799. break;
  800. }
  801. }
  802. // There is room left in the buffer so copy over
  803. // as much data from the request as will fit.
  804. //
  805. Assert(m_cbBufUsed < CB_BUF);
  806. DWORD cbToWrite = min(CB_BUF - m_cbBufUsed,
  807. m_cbRequest - m_cbRequestDone);
  808. Assert(m_pbRequest);
  809. memcpy(&m_rgbBuf[m_cbBufUsed],
  810. m_pbRequest + m_cbRequestDone,
  811. cbToWrite);
  812. m_cbBufUsed += cbToWrite;
  813. m_cbRequestDone += cbToWrite;
  814. }
  815. return sc;
  816. }
  817. template<class _RawStream, UINT CB_BUF>
  818. SCODE
  819. CBufferedStream<_RawStream, CB_BUF>::ScCopyFromInt()
  820. {
  821. SCODE sc = S_OK;
  822. // Loop around alternately filling and flushing the buffer until
  823. // we finish the request or until a buffer flush pends.
  824. //
  825. while ( m_cbRequestDone < m_cbRequest )
  826. {
  827. // If there is no room left to write to the buffer then flush
  828. // the buffer to the raw stream.
  829. //
  830. if (CB_BUF == m_cbBufUsed)
  831. {
  832. sc = ScFlushBuffer();
  833. if (FAILED(sc))
  834. {
  835. if (E_PENDING != sc)
  836. DebugTrace("CBufferedStream::ScCopyFromInt() - ScFlushBuffer() failed 0x%08lX\n", sc);
  837. break;
  838. }
  839. }
  840. // There is room left in the buffer so copy over
  841. // as much data from the request as will fit.
  842. //
  843. Assert(m_cbBufUsed < CB_BUF);
  844. UINT cbCopied = 0;
  845. DWORD cbToCopy = min(CB_BUF - m_cbBufUsed,
  846. m_cbRequest - m_cbRequestDone);
  847. Assert(m_pdsRequest);
  848. sc = m_pdsRequest->ScRead(&m_rgbBuf[m_cbBufUsed],
  849. cbToCopy,
  850. &cbCopied);
  851. if (FAILED(sc))
  852. {
  853. Assert(E_PENDING != sc);
  854. DebugTrace("CBufferedStream::ScCopyFromInt() - ScRead() from source buffer failed 0x%08lX\n", sc);
  855. break;
  856. }
  857. m_cbBufUsed += cbCopied;
  858. m_cbRequestDone += cbCopied;
  859. // Even if the clients requested to read certain amount of bytes to be read,
  860. // they may be wrong in their estimates, so let us be really smart about the
  861. // case and check if the end of the stream has been reached
  862. //
  863. if (m_pdsRequest->FEnd())
  864. {
  865. // Make sure that we certainly go out of the loop in the case we finished
  866. //
  867. m_cbRequest = m_cbRequestDone;
  868. break;
  869. }
  870. }
  871. return sc;
  872. }
  873. template<class _RawStream, UINT CB_BUF>
  874. VOID
  875. CBufferedStream<_RawStream, CB_BUF>::WriteComplete( UINT cbWritten,
  876. HRESULT hr )
  877. {
  878. // Update our internal state with the amount of buffered data that we
  879. // flushed. We only want to do this IF the call was successful....
  880. // RawWriteComplete() asserts that cbWritten == m_cbBufUsed, which will
  881. // not be true if the write failed.
  882. //
  883. if (SUCCEEDED(hr))
  884. RawWriteComplete(cbWritten);
  885. // I/O is complete. Either the write that just completed
  886. // failed or the subsequent write completed synchronously.
  887. // Notify the appropriate observer that we are done.
  888. //
  889. if (m_pobsWrite)
  890. {
  891. // I/O was a write, not a flush
  892. //
  893. Assert(!m_pobsFlush);
  894. // If I/O succeeded then continue writing where we left off.
  895. // We are done writing only when ScWriteInt() returns S_OK
  896. // or any error other than E_PENDING.
  897. //
  898. if (SUCCEEDED(hr))
  899. {
  900. hr = ScWriteInt();
  901. if (E_PENDING == hr)
  902. return;
  903. if (FAILED(hr))
  904. DebugTrace("CBufferedStream::WriteComplete() - ScWriteInt() failed 0x%08lX\n", hr);
  905. }
  906. // Pull the external write observer from where we saved it
  907. //
  908. IAsyncWriteObserver * pobsWriteExt = m_pobsWrite;
  909. m_pobsWrite = NULL;
  910. // Complete the write by calling the client back with
  911. // total amount written for the request.
  912. //
  913. // Note that m_cbRequestDone != m_cbRequest only when there
  914. // is an error.
  915. //
  916. Assert(FAILED(hr) || m_cbRequestDone == m_cbRequest);
  917. pobsWriteExt->WriteComplete(m_cbRequestDone, hr);
  918. }
  919. else
  920. {
  921. // I/O was a flush, not a write
  922. //
  923. Assert(m_pobsFlush);
  924. // The buffer should be empty after flushing
  925. //
  926. Assert(0 == m_cbBufUsed);
  927. // Pull the external flush observer from where we saved it
  928. //
  929. IAsyncFlushObserver * pobsFlushExt = m_pobsFlush;
  930. m_pobsFlush = NULL;
  931. // Tell it that we are done.
  932. //
  933. pobsFlushExt->FlushComplete(hr);
  934. }
  935. }
  936. template<class _RawStream, UINT CB_BUF>
  937. SCODE
  938. CBufferedStream<_RawStream, CB_BUF>::ScFlushBuffer()
  939. {
  940. // We better have a stream to flush to.
  941. //
  942. Assert(m_pstmRaw);
  943. // We better have something to flush.
  944. //
  945. Assert(m_cbBufUsed > 0);
  946. // Write out all buffered data to the raw stream. If writing
  947. // pends on I/O then we will resume processing in
  948. // CBufferedStream::WriteComplete() when the I/O completes.
  949. //
  950. DWORD cbWritten = 0;
  951. SCODE sc = m_pstmRaw->ScWriteRaw(m_rgbBuf,
  952. m_cbBufUsed,
  953. &cbWritten,
  954. this);
  955. if (SUCCEEDED(sc))
  956. {
  957. // ScWriteRaw() did not pend, so update our internal state and continue.
  958. //
  959. RawWriteComplete(cbWritten);
  960. }
  961. else if (E_PENDING != sc)
  962. {
  963. DebugTrace("CBufferedStream::ScFlushBuffer() - m_pstmRaw->ScWriteRaw() failed 0x%08lX\n", sc);
  964. }
  965. return sc;
  966. }
  967. template<class _RawStream, UINT CB_BUF>
  968. VOID
  969. CBufferedStream<_RawStream, CB_BUF>::RawWriteComplete(UINT cbWrittenRaw)
  970. {
  971. // Verify that we wrote the entire buffer
  972. //
  973. Assert(cbWrittenRaw == m_cbBufUsed);
  974. // Start the buffer again from the beginning
  975. //
  976. m_cbBufUsed = 0;
  977. }
  978. template<class _RawStream, UINT CB_BUF>
  979. SCODE
  980. CBufferedStream<_RawStream, CB_BUF>::ScFlush( _RawStream& stmRaw,
  981. IAsyncFlushObserver * pobsFlushExt )
  982. {
  983. SCODE sc = S_OK;
  984. // Check parameters
  985. //
  986. Assert(!pobsFlushExt || !IsBadReadPtr(pobsFlushExt, sizeof(IAsyncFlushObserver)));
  987. // We had better not be in any I/O of any sort.
  988. //
  989. Assert(!m_pobsRead);
  990. Assert(!m_pobsFlush);
  991. Assert(!m_pobsWrite);
  992. // If there's nothing to flush then we're done.
  993. //
  994. if (m_cbBufUsed)
  995. {
  996. // Set up state for a flush
  997. //
  998. m_pstmRaw = &stmRaw;
  999. m_pobsFlush = pobsFlushExt;
  1000. // Flush buffered data to the raw stream.
  1001. //
  1002. sc = ScFlushBuffer();
  1003. // If the flush didn't pend then clear out the observer.
  1004. //
  1005. if (E_PENDING != sc)
  1006. m_pobsFlush = NULL;
  1007. }
  1008. return sc;
  1009. }
  1010. // ========================================================================
  1011. //
  1012. // CLASS CFileStreamImp
  1013. //
  1014. // Base implementation class for a file stream.
  1015. //
  1016. template<class _RawStream, class _OVL>
  1017. class CFileStreamImp
  1018. {
  1019. //
  1020. // File handle
  1021. //
  1022. auto_ref_handle m_hf;
  1023. //
  1024. // File pointer
  1025. //
  1026. _OVL m_ovl;
  1027. //
  1028. // Implementation stream is a buffered stream with a buffer size
  1029. // of 64K to optimize for file I/O.
  1030. //
  1031. // Note: this data member is declared LAST because it contains
  1032. // an internal 64K buffer that we don't want sitting between
  1033. // other member variables.
  1034. //
  1035. CBufferedStream<_RawStream, 64 * 1024> m_BufferedStream;
  1036. // NOT IMPLEMENTED
  1037. //
  1038. CFileStreamImp( const CFileStreamImp& );
  1039. CFileStreamImp& operator=( const CFileStreamImp& );
  1040. public:
  1041. // CREATORS
  1042. //
  1043. CFileStreamImp(const auto_ref_handle& hf) :
  1044. m_hf(hf)
  1045. {
  1046. memset(&m_ovl, 0, sizeof(m_ovl));
  1047. }
  1048. // ACCESSORS
  1049. //
  1050. HANDLE HFile() const
  1051. {
  1052. return m_hf.get();
  1053. }
  1054. _OVL * POverlapped()
  1055. {
  1056. return &m_ovl;
  1057. }
  1058. // MANIPULATORS
  1059. //
  1060. SCODE ScRead( _RawStream& stmRaw,
  1061. BYTE * pbToRead,
  1062. DWORD cbToRead,
  1063. DWORD * pcbRead,
  1064. IAsyncReadObserver * pobsAsyncRead )
  1065. {
  1066. return m_BufferedStream.ScRead( stmRaw,
  1067. pbToRead,
  1068. cbToRead,
  1069. pcbRead,
  1070. pobsAsyncRead );
  1071. }
  1072. SCODE ScWrite( _RawStream& stmRaw,
  1073. const BYTE * pbToWrite,
  1074. DWORD cbToWrite,
  1075. DWORD * pcbWritten,
  1076. IAsyncWriteObserver * pobsAsyncWrite )
  1077. {
  1078. return m_BufferedStream.ScWrite( stmRaw,
  1079. pbToWrite,
  1080. cbToWrite,
  1081. pcbWritten,
  1082. pobsAsyncWrite );
  1083. }
  1084. SCODE ScCopyFrom( _RawStream& stmRaw,
  1085. const IDavStream * pdsToCopy,
  1086. const DWORD cbToCopy,
  1087. DWORD * pcbCopied,
  1088. IAsyncWriteObserver * pobsAsyncWrite )
  1089. {
  1090. return m_BufferedStream.ScCopyFrom( stmRaw,
  1091. pdsToCopy,
  1092. cbToCopy,
  1093. pcbCopied,
  1094. pobsAsyncWrite );
  1095. }
  1096. SCODE ScFlush( _RawStream& stmRaw,
  1097. IAsyncFlushObserver * pobsFlush )
  1098. {
  1099. return m_BufferedStream.ScFlush( stmRaw, pobsFlush );
  1100. }
  1101. //
  1102. // Update the current file position
  1103. //
  1104. VOID UpdateFilePos(UINT cbIO)
  1105. {
  1106. //
  1107. // Check for overflow of the low 32 bits of the offset. If we are
  1108. // going to overflow then increment the high part of the offset.
  1109. //
  1110. if (m_ovl.Offset + cbIO < m_ovl.Offset)
  1111. {
  1112. ++m_ovl.OffsetHigh;
  1113. //
  1114. // OffsetHigh should NEVER overflow
  1115. //
  1116. Assert(m_ovl.OffsetHigh);
  1117. }
  1118. //
  1119. // Update the low 32 bits of the offset
  1120. //
  1121. m_ovl.Offset += cbIO;
  1122. }
  1123. };
  1124. #endif // !defined(_ASTREAM_H_)