📄 stream_utils.cpp
字号:
/* * =========================================================================== * PRODUCTION $Log: stream_utils.cpp,v $ * PRODUCTION Revision 1000.4 2004/06/01 19:40:35 gouriano * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.42 * PRODUCTION * =========================================================================== *//* $Id: stream_utils.cpp,v 1000.4 2004/06/01 19:40:35 gouriano Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information * * This software/database is a "United States Government Work" under the * terms of the United States Copyright Act. It was written as part of * the author's official duties as a United States Government employee and * thus cannot be copyrighted. This software/database is freely available * to the public for use. The National Library of Medicine and the U.S. * Government have not placed any restriction on its use or reproduction. * * Although all reasonable efforts have been taken to ensure the accuracy * and reliability of the software and data, the NLM and the U.S. * Government do not and cannot warrant the performance or results that * may be obtained by using this software or data. The NLM and the U.S. * Government disclaim all warranties, express or implied, including * warranties of performance, merchantability or fitness for any particular * purpose. * * Please cite the author in any work or product based on this material. * * =========================================================================== * * Author: Anton Lavrentiev, Denis Vakatov * * File Description: * Stream utilities: * 1. Push an arbitrary block of data back to a C++ input stream. * 2. Non-blocking read. * */#include <ncbi_pch.hpp>#include <corelib/ncbistd.hpp>#include <util/util_exception.hpp>#include <util/stream_utils.hpp>#include <string.h>#ifdef NCBI_COMPILER_MIPSPRO# define CPushback_StreambufBase CMIPSPRO_ReadsomeTolerantStreambuf#else# define CPushback_StreambufBase CNcbiStreambuf#endif //NCBI_COMPILER_MIPSPRO#ifdef HAVE_GOOD_IOS_CALLBACKS# undef HAVE_GOOD_IOS_CALLBACKS#endif#if defined(HAVE_IOS_REGISTER_CALLBACK) && \ (!defined(NCBI_COMPILER_WORKSHOP) || !defined(_MT))# define HAVE_GOOD_IOS_CALLBACKS 1#endifBEGIN_NCBI_SCOPE/***************************************************************************** * Helper class: internal streambuf to be substituted instead of * the original one in the stream, when the data are pushed back. */class CPushback_Streambuf : public CPushback_StreambufBase{ friend struct CStreamUtils;public: CPushback_Streambuf(istream& istream, CT_CHAR_TYPE* buf, streamsize buf_size, void* del_ptr); virtual ~CPushback_Streambuf();protected: virtual CT_POS_TYPE seekoff(CT_OFF_TYPE off, IOS_BASE::seekdir whence, IOS_BASE::openmode which); virtual CT_POS_TYPE seekpos(CT_POS_TYPE pos, IOS_BASE::openmode which); virtual CT_INT_TYPE overflow(CT_INT_TYPE c); virtual streamsize xsputn(const CT_CHAR_TYPE* buf, streamsize n); virtual CT_INT_TYPE underflow(void); virtual streamsize xsgetn(CT_CHAR_TYPE* buf, streamsize n); virtual streamsize showmanyc(void); virtual CT_INT_TYPE pbackfail(CT_INT_TYPE c = CT_EOF); virtual int sync(void); // declared setbuf here to only throw an exception at run-time virtual streambuf* setbuf(CT_CHAR_TYPE* buf, streamsize buf_size);private: void x_FillBuffer(streamsize max_size); void x_DropBuffer(void); istream& m_Is; // I/O stream this streambuf is attached to streambuf* m_Sb; // original streambuf CT_CHAR_TYPE* m_Buf; // == 0 when the buffer has been emptied streamsize m_BufSize; void* m_DelPtr;#ifdef HAVE_GOOD_IOS_CALLBACKS int m_Index; static void x_Callback(IOS_BASE::event, IOS_BASE&, int);#endif //HAVE_GOOD_IOS_CALLBACKS static const streamsize k_MinBufSize;};const streamsize CPushback_Streambuf::k_MinBufSize = 4096;#ifdef HAVE_GOOD_IOS_CALLBACKSvoid CPushback_Streambuf::x_Callback(IOS_BASE::event event, IOS_BASE& ios, int index){ if (event == IOS_BASE::erase_event) delete static_cast<streambuf*> (ios.pword(index));}#endif //HAVE_GOOD_IOS_CALLBACKSCPushback_Streambuf::CPushback_Streambuf(istream& is, CT_CHAR_TYPE* buf, streamsize buf_size, void* del_ptr) : m_Is(is), m_Buf(buf), m_BufSize(buf_size), m_DelPtr(del_ptr){ setp(0, 0); // unbuffered output at this level of streambuf's hierarchy setg(m_Buf, m_Buf, m_Buf + m_BufSize); m_Sb = m_Is.rdbuf(this);#ifdef HAVE_GOOD_IOS_CALLBACKS try { m_Index = m_Is.xalloc(); m_Is.pword(m_Index) = this; m_Is.register_callback(x_Callback, m_Index); } STD_CATCH_ALL("CPushback_Streambuf::CPushback_Streambuf");#endif //HAVE_GOOD_IOS_CALLBACKS}CPushback_Streambuf::~CPushback_Streambuf(){#ifdef HAVE_GOOD_IOS_CALLBACKS m_Is.pword(m_Index) = 0;#endif //HAVE_GOOD_IOS_CALLBACKS delete[] (CT_CHAR_TYPE*) m_DelPtr; if (m_Sb) { m_Is.rdbuf(m_Sb); if (dynamic_cast<CPushback_Streambuf*> (m_Sb)) delete m_Sb; }}CT_POS_TYPE CPushback_Streambuf::seekoff(CT_OFF_TYPE off, IOS_BASE::seekdir whence, IOS_BASE::openmode which){ x_DropBuffer(); if (whence == ios::cur && (which & ios::in)) { return (CT_POS_TYPE)((CT_OFF_TYPE)(-1)); } return m_Sb->PUBSEEKOFF(off, whence, which);}CT_POS_TYPE CPushback_Streambuf::seekpos(CT_POS_TYPE pos, IOS_BASE::openmode which){ x_DropBuffer(); return m_Sb->PUBSEEKPOS(pos, which);}CT_INT_TYPE CPushback_Streambuf::overflow(CT_INT_TYPE c){ if ( !CT_EQ_INT_TYPE(c, CT_EOF) ) { return m_Sb->sputc(CT_TO_CHAR_TYPE(c)); } return m_Sb->PUBSYNC() == 0 ? CT_NOT_EOF(CT_EOF) : CT_EOF;}streamsize CPushback_Streambuf::xsputn(const CT_CHAR_TYPE* buf, streamsize n){ // hope that this is an optimized copy operation (instead of overflow()s) return m_Sb->sputn(buf, n);}CT_INT_TYPE CPushback_Streambuf::underflow(void){ // we are here because there is no more data in the pushback buffer _ASSERT(gptr() && gptr() >= egptr());#ifdef NCBI_COMPILER_MIPSPRO if (m_MIPSPRO_ReadsomeGptrSetLevel && m_MIPSPRO_ReadsomeGptr != gptr()) return CT_EOF; m_MIPSPRO_ReadsomeGptr = (CT_CHAR_TYPE*)(-1L);#endif //NCBI_COMPILER_MIPSPRO x_FillBuffer(m_Sb->in_avail()); return gptr() < egptr() ? CT_TO_INT_TYPE(*gptr()) : CT_EOF;}streamsize CPushback_Streambuf::xsgetn(CT_CHAR_TYPE* buf, streamsize m){ size_t n_total = 0; while (m) { if (gptr() < egptr()) { size_t n = (size_t) m; size_t n_avail = (size_t) (egptr() - gptr()); size_t n_read = (n <= n_avail) ? n : n_avail; memcpy(buf, gptr(), n_read*sizeof(CT_CHAR_TYPE)); gbump((int) n_read); m -= (streamsize) n_read; buf += (streamsize) n_read; n_total += (streamsize) n_read; } else { x_FillBuffer(m); if (gptr() >= egptr()) break; } } return n_total;}streamsize CPushback_Streambuf::showmanyc(void){ // we are here because (according to the standard) gptr() >= egptr() _ASSERT(gptr() && gptr() >= egptr()); return m_Sb->in_avail();}CT_INT_TYPE CPushback_Streambuf::pbackfail(CT_INT_TYPE /*c*/){ /* We always maintain "usual backup condition" (27.5.2.4.3.13) after * underflow(), i.e. 1 byte backup after a good read is always possible. * That is, this function gets called only if the user tries to * back up more than once (although, some attempts may be successful, * this function call denotes that the backup area is full). */ return CT_EOF; // always fail}int CPushback_Streambuf::sync(void){ return m_Sb->PUBSYNC();}streambuf* CPushback_Streambuf::setbuf(CT_CHAR_TYPE* /*buf*/, streamsize /*buf_size*/){ NCBI_THROW(CUtilException, eWrongCommand, "CPushback_Streambuf::setbuf: not allowed"); /*NOTREACHED*/ return this;}void CPushback_Streambuf::x_FillBuffer(streamsize max_size){ _ASSERT(m_Sb); if ( !max_size ) ++max_size; CPushback_Streambuf* sb = dynamic_cast<CPushback_Streambuf*> (m_Sb); if ( sb ) { _ASSERT(&m_Is == &sb->m_Is); m_Sb = sb->m_Sb; sb->m_Sb = 0; if (sb->gptr() >= sb->egptr()) { delete sb; x_FillBuffer(max_size); return; } delete[] (CT_CHAR_TYPE*) m_DelPtr; m_Buf = sb->m_Buf; m_BufSize = sb->m_BufSize; m_DelPtr = sb->m_DelPtr; sb->m_DelPtr = 0; setg(sb->gptr(), sb->gptr(), sb->egptr()); delete sb; } else { CT_CHAR_TYPE* bp = 0; streamsize buf_size = m_DelPtr ? (streamsize)(m_Buf - (CT_CHAR_TYPE*) m_DelPtr) + m_BufSize : 0; if (buf_size < k_MinBufSize) { buf_size = k_MinBufSize; bp = new CT_CHAR_TYPE[buf_size]; } streamsize n = m_Sb->sgetn(bp ? bp : (CT_CHAR_TYPE*) m_DelPtr, min(buf_size, max_size)); if (n <= 0) { // NB: For unknown reasons WorkShop6 can return -1 from sgetn :-/ delete bp; return; } if (bp) { delete[] (CT_CHAR_TYPE*) m_DelPtr; m_DelPtr = bp; } m_Buf = (CT_CHAR_TYPE*) m_DelPtr; m_BufSize = buf_size;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -