//--------------------------------------------------------------
/**
A generic buffered stream that can be used as the base class
for hardware / network interfaces such as serial ports, tcpip
sockets and any device that acts as a I/O stream.
@ingroup io
*/
class iobuffer : public std::streambuf {
int mLock;
char * mIBuf;
char * mOBuf;
std::streamsize mBufSize;
protected:
//--------------------------------------------------------------
/**
Default constructor that provides an abstract base class,
only inheriting classes may be instantiated.
*/
iobuffer ()
: mLock (0)
, mIBuf(NULL)
, mOBuf(NULL)
{
allocate(8192);
}
//--------------------------------------------------------------
/** destructor */
virtual ~iobuffer () {
if (is_locked()) {
std::cout << "what duh? what should I do now...wait...maybe." <<
std::endl;
}
deallocate();
}
public:
//--------------------------------------------------------------
/**
Returns the number of bytes that may be read from the device.
If the device is not open or has been closed, a 0 will be
returned. If a 0 is returned the caller should check whether
this was due to an invalid device by using the is_open method,
else the device's receive buffer is empty.
@todo investigate whether or not to use showmanyc protected
sstream
*/
virtual std::streamsize avail () = 0;
//--------------------------------------------------------------
/**
The low-level command that sends the specified binary character
sequence to the device. A EOF (-1) will be returned if a failure
occurs, else the number of bytes successfully sent will be
returned.
*/
virtual int send (const char * s, size_t n) = 0;
//--------------------------------------------------------------
/**
Attempts to receive a maximum number of n characters from the
device, and copy them into the specified s buffer.
*/
virtual int recv (char * s, size_t n) = 0;
//--------------------------------------------------------------
/**
*/
bool is_locked () const {
return (mLock != 0);
}
//--------------------------------------------------------------
void lock () {
mLock = 1;
}
//--------------------------------------------------------------
void unlock () {
mLock = 0;
}
//--------------------------------------------------------------
void deallocate () {
if (mIBuf) {
delete[] mIBuf;
}
if (mOBuf) {
delete[] mOBuf;
}
mIBuf = NULL;
mOBuf = NULL;
mBufSize = 0;
}
//--------------------------------------------------------------
void allocate (size_t len) {
deallocate();
mBufSize = len;
// allocate 2 extra characters to enable
// null terminated unicode padding
mIBuf = new char[mBufSize+2];
mOBuf = new char[mBufSize+2];
setg(mIBuf, mIBuf+mBufSize, mIBuf+mBufSize);
setp(mOBuf, mOBuf+mBufSize);
// TODO: throw memory exception in case of failure
}
protected:
//--------------------------------------------------------------
/** pure stream methods */
//--------------------------------------------------------------
//--------------------------------------------------------------
int flush () {
int n = static_cast<int>(pptr() - pbase());
_send(mOBuf, n);
pbump(-n);
return n;
}
//--------------------------------------------------------------
virtual int sync () {
if (flush() == EOF) {
return -1;
}
return 0;
}
//--------------------------------------------------------------
virtual int_type overflow (int_type c) {
if (c != EOF) {
*pptr() = c;
pbump(1);
}
if (flush() == EOF) {
return EOF;
}
return c;
}
//--------------------------------------------------------------
/**
*/
virtual int_type underflow () {
// is read position before end of buffer?
if (gptr() < egptr()) {
return *gptr();
}
std::streamsize n = avail();
if (n == 0) {
return EOF; // no more characters to read
}
if (n > mBufSize) {
n = mBufSize; // if incoming data exceeds buffer size - throttle
it.
}
std::streamsize len = _recv(mIBuf, n);
if (len == -1) {
return EOF; // ERROR
}
if (len == 0) {
return EOF; // ERROR
}
setg(mIBuf, mIBuf, mIBuf+len);
mIBuf[len] = 0; //null terminate (not really necessary)
return ((unsigned char)(*gptr()));
}
//--------------------------------------------------------------
/**
Overrides the base xsgetn method, and enables faster through put
when reading from the device.
*/
virtual std::streamsize xsgetn(char * s, std::streamsize n) {
std::streamsize len = _recv(mIBuf, n);
return len;
}
private:
//--------------------------------------------------------------
virtual int _send (const char * s, size_t n) {
return send(s, n);
}
//--------------------------------------------------------------
virtual int _recv (char * s, size_t n) {
return recv(s, n);
}
};