286 lines
5.5 KiB
C++
Executable File
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
|
|
|
|
|