#ifndef __JLANG__JFILESTREAMBUFFER__ #define __JLANG__JFILESTREAMBUFFER__ #include #include #include #include #include "JLang/JFile.hh" /** * \author mdejong */ namespace JLANG {} namespace JPP { using namespace JLANG; } namespace JLANG { /** * Input file stream buffer. */ class JFileInputStreamBuffer : protected virtual std::vector, public virtual std::streambuf { public: typedef traits_type::int_type int_type; /** * Constructor. * * \param file file * \param size size of internal buffer * \param put_back number of put back characters */ JFileInputStreamBuffer(const JAbstractFile& file, const std::size_t size = 65536, const std::size_t put_back = 8) : in (file), memory(put_back) { resize(size + put_back), setg(this->data(), this->data(), this->data()); } /** * Check underflow. * This method reads as many bytes as possible. * * \return first character if OK; else EOF */ virtual int_type underflow() override { if (gptr() >= egptr()) { char* __begin = this->data(); if (eback() == __begin) { // push put back characters memmove(__begin, egptr() - memory, memory); __begin += memory; } const size_t len = in.read(__begin, this->size() - (__begin - this->data())); if (len != 0) setg(this->data(), __begin, __begin + len); else return traits_type::eof(); } return *gptr(); } /** * Check availability of input. * This method returns true if at least one byte can be read without blocking. * * \param timeout timeout * \return true if ready to read; else false */ bool in_avail(JTimeval timeout = JTimeval::min()) const { return JFileDescriptorMask(in).in_avail(timeout); } protected: JFile in; std::size_t memory; private: JFileInputStreamBuffer(const JFileInputStreamBuffer&); JFileInputStreamBuffer(JFileInputStreamBuffer&&); JFileInputStreamBuffer& operator=(const JFileInputStreamBuffer&); JFileInputStreamBuffer& operator=(JFileInputStreamBuffer&&); }; /** * Output file stream buffer. */ class JFileOutputStreamBuffer : protected virtual std::vector, public virtual std::streambuf { public: typedef traits_type::int_type int_type; typedef std::streamsize streamsize; /** * Constructor. * * \param file file * \param size size of internal buffer */ JFileOutputStreamBuffer(const JAbstractFile& file, const std::size_t size = 65536) : out (file) { // reserve one byte for overflow character resize(size); setp(this->data(), this->data() + this->size() - 1); } /** * Destructor. */ virtual ~JFileOutputStreamBuffer() { sync(); } /** * Check overflow. * This method writes one byte if possible. * * \param c character * \return c if OK; else EOF */ virtual int_type overflow(int_type c) override { if (c != traits_type::eof()) { *pptr() = (char) c; pbump(1); if (flush() == traits_type::eof()) { return traits_type::eof(); } } return c; } /** * Synchronise buffer. */ virtual int sync() override { if (flush() == traits_type::eof()) return -1; else return 0; } /** * Check availability of output. * This method returns true if at least one byte can be written without blocking. * * \param timeout timeout * \return true if ready to write; else false */ bool out_avail(JTimeval timeout = JTimeval::min()) const { return JFileDescriptorMask(out).out_avail(timeout); } protected: /** * Flush internal buffer. */ int flush() { const int len = pptr() - pbase(); if (len != 0) { if (out.write(this->data(), len) != len) { return traits_type::eof(); } pbump(-len); } return len; } JFile out; private: JFileOutputStreamBuffer(const JFileOutputStreamBuffer&); JFileOutputStreamBuffer(JFileOutputStreamBuffer&&); JFileOutputStreamBuffer& operator=(const JFileOutputStreamBuffer&); JFileOutputStreamBuffer& operator=(JFileOutputStreamBuffer&&); }; /** * Input and output file stream buffer. */ class JFileStreamBuffer : public JFileInputStreamBuffer, public JFileOutputStreamBuffer { public: /** * Constructor. * * \param in input file * \param out output file * \param size size of internal buffer * \param put_back number of put back characters */ JFileStreamBuffer(const JAbstractFile& in, const JAbstractFile& out, const std::size_t size = 65536, const std::size_t put_back = 8) : JFileInputStreamBuffer (in, size, put_back), JFileOutputStreamBuffer(out, size) {} }; } #endif