diff options
Diffstat (limited to 'indra/llmessage/llbufferstream.cpp')
-rw-r--r-- | indra/llmessage/llbufferstream.cpp | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/indra/llmessage/llbufferstream.cpp b/indra/llmessage/llbufferstream.cpp new file mode 100644 index 0000000000..684548b408 --- /dev/null +++ b/indra/llmessage/llbufferstream.cpp @@ -0,0 +1,265 @@ +/** + * @file llbufferstream.cpp + * @author Phoenix + * @date 2005-10-10 + * @brief Implementation of the buffer iostream classes + * + * Copyright (c) 2005-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#include "linden_common.h" +#include "llbufferstream.h" + +#include "llbuffer.h" +#include "llmemtype.h" + +static const S32 DEFAULT_OUTPUT_SEGMENT_SIZE = 1024 * 4; + +/* + * LLBufferStreamBuf + */ +LLBufferStreamBuf::LLBufferStreamBuf( + const LLChannelDescriptors& channels, + LLBufferArray* buffer) : + mChannels(channels), + mBuffer(buffer) +{ + LLMemType m1(LLMemType::MTYPE_IO_BUFFER); +} + +LLBufferStreamBuf::~LLBufferStreamBuf() +{ + LLMemType m1(LLMemType::MTYPE_IO_BUFFER); + sync(); +} + +// virtual +int LLBufferStreamBuf::underflow() +{ + LLMemType m1(LLMemType::MTYPE_IO_BUFFER); + //lldebugs << "LLBufferStreamBuf::underflow()" << llendl; + if(!mBuffer) + { + return EOF; + } + LLSegment segment; + LLBufferArray::segment_iterator_t it; + U8* last_pos = (U8*)gptr(); + if(last_pos) --last_pos; + + LLBufferArray::segment_iterator_t end = mBuffer->endSegment(); + + // Get iterator to full segment containing last_pos + // and construct sub-segment starting at last_pos. + // Note: segment may != *it at this point + it = mBuffer->constructSegmentAfter(last_pos, segment); + if(it == end) + { + return EOF; + } + + // Iterate through segments to find a non-empty segment on input channel. + while((!segment.isOnChannel(mChannels.in()) || (segment.size() == 0))) + { + ++it; + if(it == end) + { + return EOF; + } + + segment = *it; + } + + char* start = (char*)segment.data(); + setg(start, start, start + segment.size()); + return *gptr(); +} + +// virtual +int LLBufferStreamBuf::overflow(int c) +{ + LLMemType m1(LLMemType::MTYPE_IO_BUFFER); + if(!mBuffer) + { + return EOF; + } + if(EOF == c) + { + // if someone puts an EOF, I suppose we should sync and return + // success. + if(0 == sync()) + { + return 1; + } + else + { + return EOF; + } + } + + // since we got here, we have a buffer, and we have a character to + // put on it. + LLBufferArray::segment_iterator_t it; + it = mBuffer->makeSegment(mChannels.out(), DEFAULT_OUTPUT_SEGMENT_SIZE); + if(it != mBuffer->endSegment()) + { + char* start = (char*)(*it).data(); + (*start) = (char)(c); + setp(start + 1, start + (*it).size()); + return c; + } + else + { + return EOF; + } +} + +// virtual +int LLBufferStreamBuf::sync() +{ + LLMemType m1(LLMemType::MTYPE_IO_BUFFER); + int return_value = -1; + if(!mBuffer) + { + return return_value; + } + + // set the put pointer so that we force an overflow on the next + // write. + U8* address = (U8*)pptr(); + setp(NULL, NULL); + + // *NOTE: I bet we could just --address. Need to think about that. + address = mBuffer->seek(mChannels.out(), address, -1); + if(address) + { + LLBufferArray::segment_iterator_t it; + it = mBuffer->splitAfter(address); + LLBufferArray::segment_iterator_t end = mBuffer->endSegment(); + if(it != end) + { + ++it; + if(it != end) + { + mBuffer->eraseSegment(it); + } + return_value = 0; + } + } + else + { + // nothing was put on the buffer, so the sync() is a no-op. + return_value = 0; + } + return return_value; +} + +// virtual +#if( LL_WINDOWS || __GNUC__ > 2) +LLBufferStreamBuf::pos_type LLBufferStreamBuf::seekoff( + LLBufferStreamBuf::off_type off, + std::ios::seekdir way, + std::ios::openmode which) +#else +streampos LLBufferStreamBuf::seekoff( + streamoff off, + std::ios::seekdir way, + std::ios::openmode which) +#endif +{ + LLMemType m1(LLMemType::MTYPE_IO_BUFFER); + if(!mBuffer + || ((way == std::ios::beg) && (off < 0)) + || ((way == std::ios::end) && (off > 0))) + { + return -1; + } + U8* address = NULL; + if(which & std::ios::in) + { + U8* base_addr = NULL; + switch(way) + { + case std::ios::end: + base_addr = (U8*)LLBufferArray::npos; + break; + case std::ios::cur: + // get the current get pointer and adjust it for buffer + // array semantics. + base_addr = (U8*)gptr(); + break; + case std::ios::beg: + default: + // NULL is fine + break; + } + address = mBuffer->seek(mChannels.in(), base_addr, off); + if(address) + { + LLBufferArray::segment_iterator_t iter; + iter = mBuffer->getSegment(address); + char* start = (char*)(*iter).data(); + setg(start, (char*)address, start + (*iter).size()); + } + else + { + address = (U8*)(-1); + } + } + if(which & std::ios::out) + { + U8* base_addr = NULL; + switch(way) + { + case std::ios::end: + base_addr = (U8*)LLBufferArray::npos; + break; + case std::ios::cur: + // get the current put pointer and adjust it for buffer + // array semantics. + base_addr = (U8*)pptr(); + break; + case std::ios::beg: + default: + // NULL is fine + break; + } + address = mBuffer->seek(mChannels.out(), base_addr, off); + if(address) + { + LLBufferArray::segment_iterator_t iter; + iter = mBuffer->getSegment(address); + setp((char*)address, (char*)(*iter).data() + (*iter).size()); + } + else + { + address = (U8*)(-1); + } + } + +#if( LL_WINDOWS || __GNUC__ > 2 ) + S32 rv = (S32)(intptr_t)address; + return (pos_type)rv; +#else + return (streampos)address; +#endif +} + + +/* + * LLBufferStream + */ +LLBufferStream::LLBufferStream( + const LLChannelDescriptors& channels, + LLBufferArray* buffer) : + std::iostream(&mStreamBuf), + mStreamBuf(channels, buffer) +{ + LLMemType m1(LLMemType::MTYPE_IO_BUFFER); +} + +LLBufferStream::~LLBufferStream() +{ + LLMemType m1(LLMemType::MTYPE_IO_BUFFER); +} |