BufferedBidirectionalStreamBuf.h 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. //
  2. // BufferedBidirectionalStreamBuf.h
  3. //
  4. // Library: Foundation
  5. // Package: Streams
  6. // Module: StreamBuf
  7. //
  8. // Definition of template BasicBufferedBidirectionalStreamBuf and class BufferedBidirectionalStreamBuf.
  9. //
  10. // Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
  11. // and Contributors.
  12. //
  13. // SPDX-License-Identifier: BSL-1.0
  14. //
  15. #ifndef Foundation_BufferedBidirectionalStreamBuf_INCLUDED
  16. #define Foundation_BufferedBidirectionalStreamBuf_INCLUDED
  17. #include "Poco/Foundation.h"
  18. #include "Poco/BufferAllocator.h"
  19. #include "Poco/StreamUtil.h"
  20. #include <streambuf>
  21. #include <iosfwd>
  22. #include <ios>
  23. namespace Poco {
  24. template <typename ch, typename tr, typename ba = BufferAllocator<ch> >
  25. class BasicBufferedBidirectionalStreamBuf: public std::basic_streambuf<ch, tr>
  26. /// This is an implementation of a buffered bidirectional
  27. /// streambuf that greatly simplifies the implementation of
  28. /// custom streambufs of various kinds.
  29. /// Derived classes only have to override the methods
  30. /// readFromDevice() or writeToDevice().
  31. ///
  32. /// In contrast to BasicBufferedStreambuf, this class supports
  33. /// simultaneous read and write access, so in addition to
  34. /// istream and ostream this streambuf can also be used
  35. /// for implementing an iostream.
  36. {
  37. protected:
  38. typedef std::basic_streambuf<ch, tr> Base;
  39. typedef std::basic_ios<ch, tr> IOS;
  40. typedef ch char_type;
  41. typedef tr char_traits;
  42. typedef ba Allocator;
  43. typedef typename Base::int_type int_type;
  44. typedef typename Base::pos_type pos_type;
  45. typedef typename Base::off_type off_type;
  46. typedef typename IOS::openmode openmode;
  47. public:
  48. BasicBufferedBidirectionalStreamBuf(std::streamsize bufferSize, openmode mode):
  49. _bufsize(bufferSize),
  50. _pReadBuffer(Allocator::allocate(_bufsize)),
  51. _pWriteBuffer(Allocator::allocate(_bufsize)),
  52. _mode(mode)
  53. {
  54. resetBuffers();
  55. }
  56. ~BasicBufferedBidirectionalStreamBuf()
  57. {
  58. Allocator::deallocate(_pReadBuffer, _bufsize);
  59. Allocator::deallocate(_pWriteBuffer, _bufsize);
  60. }
  61. virtual int_type overflow(int_type c)
  62. {
  63. if (!(_mode & IOS::out)) return char_traits::eof();
  64. if (flushBuffer() == std::streamsize(-1)) return char_traits::eof();
  65. if (c != char_traits::eof())
  66. {
  67. *this->pptr() = char_traits::to_char_type(c);
  68. this->pbump(1);
  69. }
  70. return c;
  71. }
  72. virtual int_type underflow()
  73. {
  74. if (!(_mode & IOS::in)) return char_traits::eof();
  75. if (this->gptr() && (this->gptr() < this->egptr()))
  76. return char_traits::to_int_type(*this->gptr());
  77. int putback = int(this->gptr() - this->eback());
  78. if (putback > 4) putback = 4;
  79. char_traits::move(_pReadBuffer + (4 - putback), this->gptr() - putback, putback);
  80. int n = readFromDevice(_pReadBuffer + 4, _bufsize - 4);
  81. if (n <= 0) return char_traits::eof();
  82. this->setg(_pReadBuffer + (4 - putback), _pReadBuffer + 4, _pReadBuffer + 4 + n);
  83. // return next character
  84. return char_traits::to_int_type(*this->gptr());
  85. }
  86. virtual int sync()
  87. {
  88. if (this->pptr() && this->pptr() > this->pbase())
  89. {
  90. if (flushBuffer() == -1) return -1;
  91. }
  92. return 0;
  93. }
  94. protected:
  95. void setMode(openmode mode)
  96. {
  97. _mode = mode;
  98. }
  99. openmode getMode() const
  100. {
  101. return _mode;
  102. }
  103. void resetBuffers()
  104. {
  105. this->setg(_pReadBuffer + 4, _pReadBuffer + 4, _pReadBuffer + 4);
  106. this->setp(_pWriteBuffer, _pWriteBuffer + _bufsize);
  107. }
  108. private:
  109. virtual int readFromDevice(char_type* /*buffer*/, std::streamsize /*length*/)
  110. {
  111. return 0;
  112. }
  113. virtual int writeToDevice(const char_type* /*buffer*/, std::streamsize /*length*/)
  114. {
  115. return 0;
  116. }
  117. int flushBuffer()
  118. {
  119. int n = int(this->pptr() - this->pbase());
  120. if (writeToDevice(this->pbase(), n) == n)
  121. {
  122. this->pbump(-n);
  123. return n;
  124. }
  125. return -1;
  126. }
  127. std::streamsize _bufsize;
  128. char_type* _pReadBuffer;
  129. char_type* _pWriteBuffer;
  130. openmode _mode;
  131. BasicBufferedBidirectionalStreamBuf(const BasicBufferedBidirectionalStreamBuf&);
  132. BasicBufferedBidirectionalStreamBuf& operator = (const BasicBufferedBidirectionalStreamBuf&);
  133. };
  134. //
  135. // We provide an instantiation for char.
  136. //
  137. // Visual C++ needs a workaround - explicitly importing the template
  138. // instantiation - to avoid duplicate symbols due to multiple
  139. // instantiations in different libraries.
  140. //
  141. #if defined(_MSC_VER) && defined(POCO_DLL) && !defined(Foundation_EXPORTS)
  142. template class Foundation_API BasicBufferedBidirectionalStreamBuf<char, std::char_traits<char> >;
  143. #endif
  144. typedef BasicBufferedBidirectionalStreamBuf<char, std::char_traits<char> > BufferedBidirectionalStreamBuf;
  145. } // namespace Poco
  146. #endif // Foundation_BufferedBidirectionalStreamBuf_INCLUDED