summaryrefslogtreecommitdiff
path: root/indra/llcorehttp/bufferstream.cpp
diff options
context:
space:
mode:
authorMonty Brandenberg <monty@lindenlab.com>2012-06-21 19:45:40 -0400
committerMonty Brandenberg <monty@lindenlab.com>2012-06-21 19:45:40 -0400
commit4da93b6ad91dff1de98c3c8dd3674c0544f2958b (patch)
treeb3fc5f6b24ed52333de31296746724e6a3278088 /indra/llcorehttp/bufferstream.cpp
parenta066bc1994fccae7967921980332505aac97953f (diff)
SH-3177 Add streambuf/iostream adapters to BufferArray object.
Initial version that should have enough of the plumbing to produce a working adapter. Memory test is showing 8 bytes held after one of the tests so I'm going to revisit that later. But basic functionality is there going by the unit tests.
Diffstat (limited to 'indra/llcorehttp/bufferstream.cpp')
-rw-r--r--indra/llcorehttp/bufferstream.cpp285
1 files changed, 285 insertions, 0 deletions
diff --git a/indra/llcorehttp/bufferstream.cpp b/indra/llcorehttp/bufferstream.cpp
new file mode 100644
index 0000000000..6553900eef
--- /dev/null
+++ b/indra/llcorehttp/bufferstream.cpp
@@ -0,0 +1,285 @@
+/**
+ * @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
+
+