phoenix-firestorm/indra/llcorehttp/bufferstream.cpp

286 lines
5.5 KiB
C++
Executable File

/**
* @file bufferstream.cpp
* @brief Implements the BufferStream adapter class
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2012, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "bufferstream.h"
#include "bufferarray.h"
namespace LLCore
{
BufferArrayStreamBuf::BufferArrayStreamBuf(BufferArray * array)
: mBufferArray(array),
mReadCurPos(0),
mReadCurBlock(-1),
mReadBegin(NULL),
mReadCur(NULL),
mReadEnd(NULL),
mWriteCurPos(0)
{
if (array)
{
array->addRef();
mWriteCurPos = array->mLen;
}
}
BufferArrayStreamBuf::~BufferArrayStreamBuf()
{
if (mBufferArray)
{
mBufferArray->release();
mBufferArray = NULL;
}
}
BufferArrayStreamBuf::int_type BufferArrayStreamBuf::underflow()
{
if (! mBufferArray)
{
return traits_type::eof();
}
if (mReadCur == mReadEnd)
{
// Find the next block with actual data or leave
// mCurBlock/mCur/mEnd unchanged if we're at the end
// of any block chain.
const char * new_begin(NULL), * new_end(NULL);
int new_cur_block(mReadCurBlock + 1);
while (mBufferArray->getBlockStartEnd(new_cur_block, &new_begin, &new_end))
{
if (new_begin != new_end)
{
break;
}
++new_cur_block;
}
if (new_begin == new_end)
{
return traits_type::eof();
}
mReadCurBlock = new_cur_block;
mReadBegin = mReadCur = new_begin;
mReadEnd = new_end;
}
return traits_type::to_int_type(*mReadCur);
}
BufferArrayStreamBuf::int_type BufferArrayStreamBuf::uflow()
{
const int_type ret(underflow());
if (traits_type::eof() != ret)
{
++mReadCur;
++mReadCurPos;
}
return ret;
}
BufferArrayStreamBuf::int_type BufferArrayStreamBuf::pbackfail(int_type ch)
{
if (! mBufferArray)
{
return traits_type::eof();
}
if (mReadCur == mReadBegin)
{
// Find the previous block with actual data or leave
// mCurBlock/mBegin/mCur/mEnd unchanged if we're at the
// beginning of any block chain.
const char * new_begin(NULL), * new_end(NULL);
int new_cur_block(mReadCurBlock - 1);
while (mBufferArray->getBlockStartEnd(new_cur_block, &new_begin, &new_end))
{
if (new_begin != new_end)
{
break;
}
--new_cur_block;
}
if (new_begin == new_end)
{
return traits_type::eof();
}
mReadCurBlock = new_cur_block;
mReadBegin = new_begin;
mReadEnd = mReadCur = new_end;
}
if (traits_type::eof() != ch && mReadCur[-1] != ch)
{
return traits_type::eof();
}
--mReadCurPos;
return traits_type::to_int_type(*--mReadCur);
}
std::streamsize BufferArrayStreamBuf::showmanyc()
{
if (! mBufferArray)
{
return -1;
}
return mBufferArray->mLen - mReadCurPos;
}
BufferArrayStreamBuf::int_type BufferArrayStreamBuf::overflow(int c)
{
if (! mBufferArray || mWriteCurPos > mBufferArray->mLen)
{
return traits_type::eof();
}
const size_t wrote(mBufferArray->write(mWriteCurPos, &c, 1));
mWriteCurPos += wrote;
return wrote ? c : traits_type::eof();
}
std::streamsize BufferArrayStreamBuf::xsputn(const char * src, std::streamsize count)
{
if (! mBufferArray || mWriteCurPos > mBufferArray->mLen)
{
return 0;
}
const size_t wrote(mBufferArray->write(mWriteCurPos, src, count));
mWriteCurPos += wrote;
return wrote;
}
std::streampos BufferArrayStreamBuf::seekoff(std::streamoff off,
std::ios_base::seekdir way,
std::ios_base::openmode which)
{
std::streampos ret(-1);
if (! mBufferArray)
{
return ret;
}
if (std::ios_base::in == which)
{
size_t pos(0);
switch (way)
{
case std::ios_base::beg:
pos = off;
break;
case std::ios_base::cur:
pos = mReadCurPos += off;
break;
case std::ios_base::end:
pos = mBufferArray->mLen - off;
break;
default:
return ret;
}
if (pos >= mBufferArray->size())
{
pos = (std::max)(size_t(0), mBufferArray->size() - 1);
}
size_t ba_offset(0);
int block(mBufferArray->findBlock(pos, &ba_offset));
if (block < 0)
return ret;
const char * start(NULL), * end(NULL);
if (! mBufferArray->getBlockStartEnd(block, &start, &end))
return ret;
mReadCurBlock = block;
mReadBegin = start;
mReadCur = start + ba_offset;
mReadEnd = end;
ret = mReadCurPos = pos;
}
else if (std::ios_base::out == which)
{
size_t pos(0);
switch (way)
{
case std::ios_base::beg:
pos = off;
break;
case std::ios_base::cur:
pos = mWriteCurPos += off;
break;
case std::ios_base::end:
pos = mBufferArray->mLen - off;
break;
default:
return ret;
}
if (pos < 0)
return ret;
if (pos > mBufferArray->size())
{
pos = mBufferArray->size();
}
ret = mWriteCurPos = pos;
}
return ret;
}
BufferArrayStream::BufferArrayStream(BufferArray * ba)
: std::iostream(&mStreamBuf),
mStreamBuf(ba)
{}
BufferArrayStream::~BufferArrayStream()
{}
} // end namespace LLCore