| // Copyright (c) 2010 The WebM project authors. All Rights Reserved. | |
| // | |
| // Use of this source code is governed by a BSD-style license | |
| // that can be found in the LICENSE file in the root of the source | |
| // tree. An additional intellectual property rights grant can be found | |
| // in the file PATENTS. All contributing project authors may | |
| // be found in the AUTHORS file in the root of the source tree. | |
| #pragma once | |
| //#include <streambuf> | |
| template<typename elem_t, typename traits_t> | |
| class basic_dbgstreambuf : public std::basic_streambuf<elem_t, traits_t> | |
| { | |
| public: | |
| //typedef std::basic_streambuf<elem_t, traits_t> base_t; | |
| basic_dbgstreambuf(); | |
| ~basic_dbgstreambuf(); | |
| protected: | |
| std::streamsize plen() const; | |
| std::streamsize ppos() const; | |
| void ppos(std::streamsize); | |
| int_type overflow(int_type c); | |
| std::streamsize xsputn(const elem_t*, std::streamsize); | |
| int sync(); | |
| pos_type seekoff( | |
| off_type off, | |
| std::ios_base::seekdir way, | |
| std::ios_base::openmode which); | |
| pos_type seekpos( | |
| pos_type pos, | |
| std::ios_base::openmode which); | |
| private: | |
| basic_dbgstreambuf(const basic_dbgstreambuf<elem_t, traits_t>&); | |
| basic_dbgstreambuf<elem_t, traits_t>& | |
| operator=(const basic_dbgstreambuf<elem_t, traits_t>&); | |
| //void resize(std::basic_string<TCHAR>::size_type); | |
| //std::basic_string<TCHAR> m_buf; | |
| elem_t* m_buf; | |
| }; | |
| template<typename elem_t, typename traits_t> | |
| inline basic_dbgstreambuf<elem_t, traits_t>::basic_dbgstreambuf() | |
| : m_buf(0) | |
| { | |
| //resize(1); | |
| } | |
| template<typename elem_t, typename traits_t> | |
| inline basic_dbgstreambuf<elem_t, traits_t>::~basic_dbgstreambuf() | |
| { | |
| sync(); | |
| setp(0, 0, 0); | |
| delete[] m_buf; | |
| } | |
| template<typename elem_t, typename traits_t> | |
| inline std::streamsize basic_dbgstreambuf<elem_t, traits_t>::plen() const | |
| { | |
| const ptrdiff_t result = epptr() - pptr(); | |
| return static_cast<std::streamsize>(result); | |
| } | |
| template<typename elem_t, typename traits_t> | |
| inline std::streamsize basic_dbgstreambuf<elem_t, traits_t>::ppos() const | |
| { | |
| const ptrdiff_t result = pptr() - pbase(); | |
| return static_cast<std::streamsize>(result); | |
| } | |
| template<typename elem_t, typename traits_t> | |
| inline void basic_dbgstreambuf<elem_t, traits_t>::ppos(std::streamsize pos) | |
| { | |
| pbump(int(pos) - int(ppos())); | |
| } | |
| template<typename elem_t> | |
| void OutputDebugStringX(const elem_t*); | |
| template<> | |
| inline void OutputDebugStringX(const char* str) | |
| { | |
| ::OutputDebugStringA(str); | |
| } | |
| template<> | |
| inline void OutputDebugStringX(const wchar_t* str) | |
| { | |
| ::OutputDebugStringW(str); | |
| } | |
| template<typename elem_t, typename traits_t> | |
| inline typename basic_dbgstreambuf<elem_t, traits_t>::int_type | |
| basic_dbgstreambuf<elem_t, traits_t>::overflow(int_type c_) | |
| { | |
| if (traits_t::eq_int_type(traits_t::eof(), c_)) | |
| return traits_t::eof(); | |
| const elem_t c = traits_t::to_char_type(c_); | |
| //sync(); | |
| //NOTE: No, we can't do this here, since dbgview will | |
| //break the text across lines when the auto-scroll | |
| //option is enabled. | |
| const ptrdiff_t oldlen = epptr() - pbase(); | |
| const ptrdiff_t newlen = oldlen ? 2 * oldlen : 1; | |
| if (elem_t* const newbuf = new (std::nothrow) elem_t[newlen + 1]) | |
| { | |
| const std::streamsize pos = ppos(); | |
| #if _MSC_VER >= 1400 | |
| const size_t size_in_bytes = newlen * sizeof(elem_t); | |
| const size_t pos_ = static_cast<size_t>(pos); | |
| traits_t::_Copy_s(newbuf, size_in_bytes, pbase(), pos_); | |
| #else | |
| traits_t::copy(newbuf, pbase(), pos); | |
| #endif | |
| setp(newbuf, newbuf + pos, newbuf + newlen); | |
| delete[] m_buf; | |
| m_buf = newbuf; | |
| *pptr() = c; | |
| pbump(1); | |
| return traits_t::not_eof(c_); | |
| } | |
| if (oldlen) | |
| { | |
| sync(); | |
| *pbase() = c; | |
| pbump(1); | |
| } | |
| else | |
| { | |
| const elem_t str[2] = { c, elem_t() }; | |
| OutputDebugStringX(str); | |
| } | |
| return traits_t::not_eof(c_); | |
| } | |
| template<typename elem_t, typename traits_t> | |
| inline std::streamsize basic_dbgstreambuf<elem_t, traits_t>::xsputn( | |
| const elem_t* str, | |
| std::streamsize n) | |
| { | |
| if (n <= plen()) | |
| { | |
| #if _MSC_VER >= 1400 | |
| const size_t plen_ = static_cast<size_t>(plen()); | |
| const size_t size_in_bytes = plen_ * sizeof(elem_t); | |
| const size_t nn = static_cast<size_t>(n); | |
| traits_t::_Copy_s(pptr(), size_in_bytes, str, nn); | |
| #else | |
| traits_t::copy(pptr(), str, n); | |
| #endif | |
| const int off = static_cast<int>(n); | |
| pbump(off); | |
| return n; | |
| } | |
| const std::streamsize pos = ppos(); | |
| const std::streamsize newlen = pos + n; | |
| const size_t newlen_ = static_cast<size_t>(newlen); | |
| if (elem_t* const newbuf = new (std::nothrow) elem_t[newlen_ + 1]) | |
| { | |
| #if _MSC_VER >= 1400 | |
| size_t size_in_bytes = newlen_ * sizeof(elem_t); | |
| const size_t pos_ = static_cast<size_t>(pos); | |
| traits_t::_Copy_s(newbuf, size_in_bytes, pbase(), pos_); | |
| #else | |
| traits_t::copy(newbuf, pbase(), pos); | |
| #endif | |
| setp(newbuf, newbuf + pos, newbuf + newlen); | |
| delete[] m_buf; | |
| m_buf = newbuf; | |
| #if _MSC_VER >= 1400 | |
| const size_t plen_ = static_cast<size_t>(plen()); | |
| size_in_bytes = plen_ * sizeof(elem_t); | |
| const size_t nn = static_cast<size_t>(n); | |
| traits_t::_Copy_s(pptr(), size_in_bytes, str, nn); | |
| #else | |
| traits_t::copy(pptr(), str, n); | |
| #endif | |
| const int off = static_cast<int>(n); | |
| pbump(off); | |
| return n; | |
| } | |
| const ptrdiff_t oldlen_ = epptr() - pbase(); | |
| if (oldlen_ == 0) | |
| { | |
| elem_t buf[2]; | |
| buf[1] = elem_t(); | |
| for (std::streamsize i = 0; i < n; ++i) | |
| { | |
| buf[0] = *str++; | |
| OutputDebugStringX(buf); | |
| } | |
| return n; | |
| } | |
| std::streamsize nn = n; | |
| if (std::streamsize len = plen()) | |
| { | |
| #if _MSC_VER >= 1400 | |
| const size_t len_ = static_cast<size_t>(len); | |
| const size_t size_in_bytes = len_ * sizeof(elem_t); | |
| traits_t::_Copy_s(pptr(), size_in_bytes, str, len_); | |
| #else | |
| traits_t::copy(pptr(), str, len); | |
| #endif | |
| const int off = static_cast<int>(len); | |
| pbump(off); | |
| str += len; | |
| nn -= len; | |
| } | |
| const std::streamsize oldlen = static_cast<std::streamsize>(oldlen_); | |
| #if _MSC_VER >= 1400 | |
| const size_t size_in_bytes = oldlen_ * sizeof(elem_t); | |
| #endif | |
| for (;;) | |
| { | |
| sync(); | |
| if (nn <= oldlen) | |
| { | |
| #if _MSC_VER >= 1400 | |
| const size_t nnn = static_cast<size_t>(nn); | |
| traits_t::_Copy_s(pbase(), size_in_bytes, str, nnn); | |
| #else | |
| traits_t::copy(pbase(), str, nn); | |
| #endif | |
| const int off = static_cast<int>(nn); | |
| pbump(off); | |
| return n; | |
| } | |
| #if _MSC_VER >= 1400 | |
| traits_t::_Copy_s(pbase(), size_in_bytes, str, oldlen_); | |
| #else | |
| traits_t::copy(pbase(), str, oldlen); | |
| #endif | |
| const int off = static_cast<int>(oldlen); | |
| pbump(off); | |
| str += oldlen; | |
| nn -= oldlen; | |
| } | |
| } | |
| template<typename elem_t, typename traits_t> | |
| inline int basic_dbgstreambuf<elem_t, traits_t>::sync() | |
| { | |
| if (ppos() == 0) //avoid unnecessary carriage return in dbgview | |
| return 0; | |
| *pptr() = elem_t(); | |
| OutputDebugStringX(pbase()); | |
| ppos(0); | |
| return 0; | |
| } | |
| //template<typename elem_t, typename traits_t> | |
| //inline void basic_dbgstreambuf<elem_t, traits_t>::resize( | |
| // std::basic_string<TCHAR>::size_type n) | |
| //{ | |
| // m_buf.resize(n); | |
| // | |
| // const TCHAR* const const_buf = m_buf.c_str(); | |
| // TCHAR* const buf = const_cast<TCHAR*>(const_buf); | |
| // | |
| // setp(buf, buf, buf + n); | |
| //} | |
| template<typename elem_t, typename traits_t> | |
| inline typename basic_dbgstreambuf<elem_t, traits_t>::pos_type | |
| basic_dbgstreambuf<elem_t, traits_t>::seekoff( | |
| off_type off, | |
| std::ios_base::seekdir way, | |
| std::ios_base::openmode which) | |
| { | |
| off_type pos = -1; | |
| if (which & std::ios_base::out) | |
| { | |
| const ptrdiff_t buflen = epptr() - pbase(); | |
| switch (way) | |
| { | |
| case std::ios_base::beg: | |
| pos = off; | |
| break; | |
| case std::ios_base::cur: | |
| pos = off_type(ppos()) + off; | |
| break; | |
| case std::ios_base::end: | |
| pos = off_type(buflen) + off; | |
| break; | |
| } | |
| if (pos < 0) | |
| pos = -1; | |
| else if (pos > off_type(buflen)) | |
| pos = -1; | |
| else | |
| ppos(pos); | |
| } | |
| return pos; | |
| } | |
| template<typename elem_t, typename traits_t> | |
| inline typename basic_dbgstreambuf<elem_t, traits_t>::pos_type | |
| basic_dbgstreambuf<elem_t, traits_t>::seekpos( | |
| pos_type pos_, | |
| std::ios_base::openmode which) | |
| { | |
| off_type pos = -1; | |
| if (which & std::ios_base::out) | |
| { | |
| pos = pos_; | |
| const ptrdiff_t buflen = epptr() - pbase(); | |
| if (pos < 0) | |
| pos = -1; | |
| else if (pos > off_type(buflen)) | |
| pos = -1; | |
| else | |
| ppos(pos); | |
| } | |
| return pos; | |
| } |