/** * @file llbufferstream.cpp * @author Phoenix * @date 2005-10-10 * @brief Implementation of the buffer iostream classes * * Copyright (c) 2005-2007, Linden Research, Inc. * * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or * online at http://secondlife.com/developers/opensource/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or * online at http://secondlife.com/developers/opensource/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. */ #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); }