diff options
Diffstat (limited to 'svl/source/misc/strmadpt.cxx')
-rw-r--r-- | svl/source/misc/strmadpt.cxx | 1048 |
1 files changed, 1048 insertions, 0 deletions
diff --git a/svl/source/misc/strmadpt.cxx b/svl/source/misc/strmadpt.cxx new file mode 100644 index 000000000000..9803f2bcc32f --- /dev/null +++ b/svl/source/misc/strmadpt.cxx @@ -0,0 +1,1048 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: strmadpt.cxx,v $ + * $Revision: 1.5.136.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svl.hxx" + +#include <functional> // needed under Solaris when including <algorithm>... + +#include <algorithm> +#include <limits> +#include <set> +#include <rtl/alloc.h> +#include <rtl/memory.h> +#include <instrm.hxx> +#include <outstrm.hxx> +#include <strmadpt.hxx> + +using namespace com::sun::star; + +//============================================================================ +class SvDataPipe_Impl +{ +public: + enum SeekResult { SEEK_BEFORE_MARKED, SEEK_OK, SEEK_PAST_END }; + +private: + struct Page + { + Page * m_pPrev; + Page * m_pNext; + sal_Int8 * m_pStart; + sal_Int8 * m_pRead; + sal_Int8 * m_pEnd; + sal_uInt32 m_nOffset; + sal_Int8 m_aBuffer[1]; + }; + + std::multiset< sal_uInt32 > m_aMarks; + Page * m_pFirstPage; + Page * m_pReadPage; + Page * m_pWritePage; + sal_Int8 * m_pReadBuffer; + sal_uInt32 m_nReadBufferSize; + sal_uInt32 m_nReadBufferFilled; + sal_uInt32 m_nPageSize; + sal_uInt32 m_nMinPages; + sal_uInt32 m_nMaxPages; + sal_uInt32 m_nPages; + bool m_bEOF; + + bool remove(Page * pPage); + +public: + inline SvDataPipe_Impl(sal_uInt32 nThePageSize = 1000, + sal_uInt32 nTheMinPages = 100, + sal_uInt32 nTheMaxPages + = std::numeric_limits< sal_uInt32 >::max()); + + ~SvDataPipe_Impl(); + + inline void setReadBuffer(sal_Int8 * pBuffer, sal_uInt32 nSize); + + sal_uInt32 read(); + + void clearReadBuffer() { m_pReadBuffer = 0; } + + sal_uInt32 write(sal_Int8 const * pBuffer, sal_uInt32 nSize); + + void setEOF() { m_bEOF = true; } + + inline bool isEOF() const; + + bool addMark(sal_uInt32 nPosition); + + bool removeMark(sal_uInt32 nPosition); + + inline sal_uInt32 getReadPosition() const; + + SeekResult setReadPosition(sal_uInt32 nPosition); +}; + +SvDataPipe_Impl::SvDataPipe_Impl(sal_uInt32 nThePageSize, + sal_uInt32 nTheMinPages, + sal_uInt32 nTheMaxPages): + m_pFirstPage(0), + m_pReadPage(0), + m_pWritePage(0), + m_pReadBuffer(0), + m_nPageSize(std::min< sal_uInt32 >( + std::max< sal_uInt32 >(nThePageSize, sal_uInt32(1)), + sal_uInt32(std::numeric_limits< sal_uInt32 >::max() + - sizeof (Page) + 1))), + m_nMinPages(std::max< sal_uInt32 >(nTheMinPages, sal_uInt32(1))), + m_nMaxPages(std::max< sal_uInt32 >(nTheMaxPages, sal_uInt32(1))), + m_nPages(0), + m_bEOF(false) +{} + +inline void SvDataPipe_Impl::setReadBuffer(sal_Int8 * pBuffer, + sal_uInt32 nSize) +{ + m_pReadBuffer = pBuffer; + m_nReadBufferSize = nSize; + m_nReadBufferFilled = 0; +} + +inline bool SvDataPipe_Impl::isEOF() const +{ + return m_bEOF && m_pReadPage == m_pWritePage + && (!m_pReadPage || m_pReadPage->m_pRead == m_pReadPage->m_pEnd); +} + +inline sal_uInt32 SvDataPipe_Impl::getReadPosition() const +{ + return m_pReadPage == 0 ? 0 : + m_pReadPage->m_nOffset + + (m_pReadPage->m_pRead + - m_pReadPage->m_aBuffer); +} + +//============================================================================ +// +// SvOutputStreamOpenLockBytes +// +//============================================================================ + +TYPEINIT1(SvOutputStreamOpenLockBytes, SvOpenLockBytes) + +//============================================================================ +// virtual +ErrCode SvOutputStreamOpenLockBytes::ReadAt(ULONG, void *, ULONG, ULONG *) + const +{ + return ERRCODE_IO_CANTREAD; +} + +//============================================================================ +// virtual +ErrCode SvOutputStreamOpenLockBytes::WriteAt(ULONG nPos, void const * pBuffer, + ULONG nCount, ULONG * pWritten) +{ + if (nPos != m_nPosition) + return ERRCODE_IO_CANTWRITE; + return FillAppend(pBuffer, nCount, pWritten); +} + +//============================================================================ +// virtual +ErrCode SvOutputStreamOpenLockBytes::Flush() const +{ + if (!m_xOutputStream.is()) + return ERRCODE_IO_CANTWRITE; + try + { + m_xOutputStream->flush(); + } + catch (io::IOException) + { + return ERRCODE_IO_CANTWRITE; + } + return ERRCODE_NONE; +} + +//============================================================================ +// virtual +ErrCode SvOutputStreamOpenLockBytes::SetSize(ULONG) +{ + return ERRCODE_IO_NOTSUPPORTED; +} + +//============================================================================ +// virtual +ErrCode SvOutputStreamOpenLockBytes::Stat(SvLockBytesStat * pStat, + SvLockBytesStatFlag) const +{ + if (pStat) + pStat->nSize = m_nPosition; + return ERRCODE_NONE; +} + +//============================================================================ +// virtual +ErrCode SvOutputStreamOpenLockBytes::FillAppend(void const * pBuffer, + ULONG nCount, + ULONG * pWritten) +{ + if (!m_xOutputStream.is()) + return ERRCODE_IO_CANTWRITE; + if (nCount > 0 + && nCount > std::numeric_limits< ULONG >::max() - m_nPosition) + { + nCount = std::numeric_limits< ULONG >::max() - m_nPosition; + if (nCount == 0) + return ERRCODE_IO_CANTWRITE; + } + try + { + m_xOutputStream-> + writeBytes(uno::Sequence< sal_Int8 >( + static_cast< sal_Int8 const * >(pBuffer), nCount)); + } + catch (io::IOException) + { + return ERRCODE_IO_CANTWRITE; + } + m_nPosition += nCount; + if (pWritten) + *pWritten = nCount; + return ERRCODE_NONE; +} + +//============================================================================ +// virtual +ULONG SvOutputStreamOpenLockBytes::Tell() const +{ + return m_nPosition; +} + +//============================================================================ +// virtual +ULONG SvOutputStreamOpenLockBytes::Seek(ULONG) +{ + return m_nPosition; +} + +//============================================================================ +// virtual +void SvOutputStreamOpenLockBytes::Terminate() +{ + if (m_xOutputStream.is()) + try + { + m_xOutputStream->closeOutput(); + } + catch (io::IOException) {} +} + +//============================================================================ +// +// SvLockBytesInputStream +// +//============================================================================ + +// virtual +uno::Any SAL_CALL SvLockBytesInputStream::queryInterface(uno::Type const & + rType) + throw (uno::RuntimeException) +{ + uno::Any + aReturn(cppu::queryInterface(rType, + static_cast< io::XInputStream * >(this), + static_cast< io::XSeekable * >(this))); + return aReturn.hasValue() ? aReturn : OWeakObject::queryInterface(rType); +} + +//============================================================================ +// virtual +void SAL_CALL SvLockBytesInputStream::acquire() throw () +{ + OWeakObject::acquire(); +} + +//============================================================================ +// virtual +void SAL_CALL SvLockBytesInputStream::release() throw () +{ + OWeakObject::release(); +} + +//============================================================================ +// virtual +sal_Int32 SAL_CALL +SvLockBytesInputStream::readBytes(uno::Sequence< sal_Int8 > & rData, + sal_Int32 nBytesToRead) + throw (io::IOException, uno::RuntimeException) +{ + OSL_ASSERT(m_nPosition >= 0); + if (!m_xLockBytes.Is()) + throw io::NotConnectedException(); + if ( + nBytesToRead < 0 || + ( + static_cast<sal_uInt64>(m_nPosition) > SAL_MAX_SIZE && + nBytesToRead > 0 + ) + ) + { + throw io::IOException(); + } + rData.realloc(nBytesToRead); + sal_Int32 nSize = 0; + while (nSize < nBytesToRead) + { + sal_Size nCount; + ErrCode nError = m_xLockBytes->ReadAt(static_cast<sal_Size>( + m_nPosition), + rData.getArray() + nSize, + nBytesToRead - nSize, &nCount); + if (nError != ERRCODE_NONE && nError != ERRCODE_IO_PENDING) + throw io::IOException(); + m_nPosition += nCount; + nSize += nCount; + if (nError == ERRCODE_NONE && nCount == 0) + break; + } + rData.realloc(nSize); + return nSize; +} + +//============================================================================ +// virtual +sal_Int32 SAL_CALL +SvLockBytesInputStream::readSomeBytes(uno::Sequence< sal_Int8 > & rData, + sal_Int32 nMaxBytesToRead) + throw (io::IOException, uno::RuntimeException) +{ + OSL_ASSERT(m_nPosition >= 0); + if (!m_xLockBytes.Is()) + throw io::NotConnectedException(); + if (static_cast<sal_uInt64>(m_nPosition) > SAL_MAX_SIZE + && nMaxBytesToRead > 0) + throw io::IOException(); + rData.realloc(nMaxBytesToRead); + sal_Size nCount = 0; + if (nMaxBytesToRead > 0) + { + ErrCode nError; + do + { + nError = m_xLockBytes->ReadAt(static_cast<sal_Size>(m_nPosition), + rData.getArray(), + nMaxBytesToRead < 0 ? + 0 : nMaxBytesToRead, + &nCount); + if (nError != ERRCODE_NONE && nError != ERRCODE_IO_PENDING) + throw io::IOException(); + m_nPosition += nCount; + } + while (nCount == 0 && nError == ERRCODE_IO_PENDING); + } + rData.realloc(sal_Int32(nCount)); + return sal_Int32(nCount); +} + +//============================================================================ +// virtual +void SAL_CALL SvLockBytesInputStream::skipBytes(sal_Int32 nBytesToSkip) + throw (io::IOException, uno::RuntimeException) +{ + if (!m_xLockBytes.Is()) + throw io::NotConnectedException(); + if (nBytesToSkip < 0) + throw io::IOException(); + if (nBytesToSkip > SAL_MAX_INT64 - m_nPosition) + throw io::BufferSizeExceededException(); + m_nPosition += nBytesToSkip; +} + +//============================================================================ +// virtual +sal_Int32 SAL_CALL SvLockBytesInputStream::available() + throw (io::IOException, uno::RuntimeException) +{ + OSL_ASSERT(m_nPosition >= 0); + if (!m_xLockBytes.Is()) + throw io::NotConnectedException(); + SvLockBytesStat aStat; + if (m_xLockBytes->Stat(&aStat, SVSTATFLAG_DEFAULT) != ERRCODE_NONE) + throw io::IOException(); + return aStat.nSize <= static_cast<sal_uInt64>(m_nPosition) ? + 0 : + static_cast<sal_Size>(aStat.nSize - m_nPosition) <= + static_cast<sal_uInt32>(SAL_MAX_INT32) ? + static_cast<sal_Int32>(aStat.nSize - m_nPosition) : + SAL_MAX_INT32; +} + +//============================================================================ +// virtual +void SAL_CALL SvLockBytesInputStream::closeInput() + throw (io::IOException, uno::RuntimeException) +{ + if (!m_xLockBytes.Is()) + throw io::NotConnectedException(); + m_xLockBytes = 0; +} + +//============================================================================ +// virtual +void SAL_CALL SvLockBytesInputStream::seek(sal_Int64 nLocation) + throw (lang::IllegalArgumentException, io::IOException, + uno::RuntimeException) +{ + if (nLocation < 0) + throw lang::IllegalArgumentException(); + if (!m_xLockBytes.Is()) + throw io::NotConnectedException(); + m_nPosition = nLocation; +} + +//============================================================================ +// virtual +sal_Int64 SAL_CALL SvLockBytesInputStream::getPosition() + throw (io::IOException, uno::RuntimeException) +{ + if (!m_xLockBytes.Is()) + throw io::NotConnectedException(); + return m_nPosition; +} + +//============================================================================ +// virtual +sal_Int64 SAL_CALL SvLockBytesInputStream::getLength() + throw (io::IOException, uno::RuntimeException) +{ + if (!m_xLockBytes.Is()) + throw io::NotConnectedException(); + SvLockBytesStat aStat; + if (m_xLockBytes->Stat(&aStat, SVSTATFLAG_DEFAULT) != ERRCODE_NONE) + throw io::IOException(); +#if SAL_TYPES_SIZEOFPOINTER > 4 // avoid warnings if sal_Size < sal_Int64 + if (aStat.nSize > static_cast<sal_uInt64>(SAL_MAX_INT64)) + throw io::IOException(); +#endif + return aStat.nSize; +} + +//============================================================================ +// +// SvInputStream +// +//============================================================================ + +bool SvInputStream::open() +{ + if (GetError() != ERRCODE_NONE) + return false; + if (!(m_xSeekable.is() || m_pPipe)) + { + if (!m_xStream.is()) + { + SetError(ERRCODE_IO_INVALIDDEVICE); + return false; + } + m_xSeekable + = uno::Reference< io::XSeekable >(m_xStream, uno::UNO_QUERY); + if (!m_xSeekable.is()) + m_pPipe = new SvDataPipe_Impl; + } + return true; +} + +//============================================================================ +// virtual +ULONG SvInputStream::GetData(void * pData, ULONG nSize) +{ + if (!open()) + { + SetError(ERRCODE_IO_CANTREAD); + return 0; + } + sal_uInt32 nRead = 0; + if (m_xSeekable.is()) + { + if (m_nSeekedFrom != STREAM_SEEK_TO_END) + { + try + { + m_xSeekable->seek(m_nSeekedFrom); + } + catch (io::IOException) + { + SetError(ERRCODE_IO_CANTREAD); + return 0; + } + m_nSeekedFrom = STREAM_SEEK_TO_END; + } + for (;;) + { + sal_Int32 nRemain + = sal_Int32( + std::min(ULONG(nSize - nRead), + ULONG(std::numeric_limits< sal_Int32 >::max()))); + if (nRemain == 0) + break; + uno::Sequence< sal_Int8 > aBuffer; + sal_Int32 nCount; + try + { + nCount = m_xStream->readBytes(aBuffer, nRemain); + } + catch (io::IOException) + { + SetError(ERRCODE_IO_CANTREAD); + return nRead; + } + rtl_copyMemory(static_cast< sal_Int8 * >(pData) + nRead, + aBuffer.getConstArray(), sal_uInt32(nCount)); + nRead += nCount; + if (nCount < nRemain) + break; + } + } + else + { + if (m_nSeekedFrom != STREAM_SEEK_TO_END) + { + SetError(ERRCODE_IO_CANTREAD); + return 0; + } + m_pPipe->setReadBuffer(static_cast< sal_Int8 * >(pData), nSize); + nRead = m_pPipe->read(); + if (nRead < nSize && !m_pPipe->isEOF()) + for (;;) + { + sal_Int32 nRemain + = sal_Int32( + std::min( + ULONG(nSize - nRead), + ULONG(std::numeric_limits< sal_Int32 >::max()))); + if (nRemain == 0) + break; + uno::Sequence< sal_Int8 > aBuffer; + sal_Int32 nCount; + try + { + nCount = m_xStream->readBytes(aBuffer, nRemain); + } + catch (io::IOException) + { + SetError(ERRCODE_IO_CANTREAD); + break; + } + m_pPipe->write(aBuffer.getConstArray(), sal_uInt32(nCount)); + nRead += m_pPipe->read(); + if (nCount < nRemain) + { + m_xStream->closeInput(); + m_pPipe->setEOF(); + break; + } + } + m_pPipe->clearReadBuffer(); + } + return nRead; +} + +//============================================================================ +// virtual +ULONG SvInputStream::PutData(void const *, ULONG) +{ + SetError(ERRCODE_IO_NOTSUPPORTED); + return 0; +} + +//============================================================================ +// virtual +void SvInputStream::FlushData() +{} + +//============================================================================ +// virtual +ULONG SvInputStream::SeekPos(ULONG nPos) +{ + if (open()) + { + if (nPos == STREAM_SEEK_TO_END) + { + if (m_nSeekedFrom == STREAM_SEEK_TO_END) + { + if (m_xSeekable.is()) + try + { + sal_Int64 nLength = m_xSeekable->getLength(); + OSL_ASSERT(nLength >= 0); + if (static_cast<sal_uInt64>(nLength) + < STREAM_SEEK_TO_END) + { + m_nSeekedFrom = Tell(); + return ULONG(nLength); + } + } + catch (io::IOException) {} + else + return Tell(); //@@@ + } + else + return Tell(); + } + else if (nPos == m_nSeekedFrom) + { + m_nSeekedFrom = STREAM_SEEK_TO_END; + return nPos; + } + else if (m_xSeekable.is()) + try + { + m_xSeekable->seek(nPos); + m_nSeekedFrom = STREAM_SEEK_TO_END; + return nPos; + } + catch (io::IOException) {} + else if (m_pPipe->setReadPosition(nPos) == SvDataPipe_Impl::SEEK_OK) + { + m_nSeekedFrom = STREAM_SEEK_TO_END; + return nPos; + } + } + SetError(ERRCODE_IO_CANTSEEK); + return Tell(); +} + +//============================================================================ +// virtual +void SvInputStream::SetSize(ULONG) +{ + SetError(ERRCODE_IO_NOTSUPPORTED); +} + +//============================================================================ +SvInputStream::SvInputStream( + com::sun::star::uno::Reference< com::sun::star::io::XInputStream > + const & + rTheStream): + m_xStream(rTheStream), + m_pPipe(0), + m_nSeekedFrom(STREAM_SEEK_TO_END) +{ + SetBufferSize(0); +} + +//============================================================================ +// virtual +SvInputStream::~SvInputStream() +{ + if (m_xStream.is()) + try + { + m_xStream->closeInput(); + } + catch (io::IOException) {} + delete m_pPipe; +} + +//============================================================================ +// virtual +USHORT SvInputStream::IsA() const +{ + return 0; +} + +//============================================================================ +// virtual +void SvInputStream::AddMark(ULONG nPos) +{ + if (open() && m_pPipe) + m_pPipe->addMark(nPos); +} + +//============================================================================ +// virtual +void SvInputStream::RemoveMark(ULONG nPos) +{ + if (open() && m_pPipe) + m_pPipe->removeMark(nPos); +} + +//============================================================================ +// +// SvOutputStream +// +//============================================================================ + +// virtual +ULONG SvOutputStream::GetData(void *, ULONG) +{ + SetError(ERRCODE_IO_NOTSUPPORTED); + return 0; +} + +//============================================================================ +// virtual +ULONG SvOutputStream::PutData(void const * pData, ULONG nSize) +{ + if (!m_xStream.is()) + { + SetError(ERRCODE_IO_CANTWRITE); + return 0; + } + ULONG nWritten = 0; + for (;;) + { + sal_Int32 nRemain + = sal_Int32( + std::min(ULONG(nSize - nWritten), + ULONG(std::numeric_limits< sal_Int32 >::max()))); + if (nRemain == 0) + break; + try + { + m_xStream->writeBytes(uno::Sequence< sal_Int8 >( + static_cast<const sal_Int8 * >(pData) + + nWritten, + nRemain)); + } + catch (io::IOException) + { + SetError(ERRCODE_IO_CANTWRITE); + break; + } + nWritten += nRemain; + } + return nWritten; +} + +//============================================================================ +// virtual +ULONG SvOutputStream::SeekPos(ULONG) +{ + SetError(ERRCODE_IO_NOTSUPPORTED); + return 0; +} + +//============================================================================ +// virtual +void SvOutputStream::FlushData() +{ + if (!m_xStream.is()) + { + SetError(ERRCODE_IO_INVALIDDEVICE); + return; + } + try + { + m_xStream->flush(); + } + catch (io::IOException) {} +} + +//============================================================================ +// virtual +void SvOutputStream::SetSize(ULONG) +{ + SetError(ERRCODE_IO_NOTSUPPORTED); +} + +//============================================================================ +SvOutputStream::SvOutputStream(uno::Reference< io::XOutputStream > const & + rTheStream): + m_xStream(rTheStream) +{ + SetBufferSize(0); +} + +//============================================================================ +// virtual +SvOutputStream::~SvOutputStream() +{ + if (m_xStream.is()) + try + { + m_xStream->closeOutput(); + } + catch (io::IOException) {} +} + +//============================================================================ +// virtual +USHORT SvOutputStream::IsA() const +{ + return 0; +} + +//============================================================================ +// +// SvDataPipe_Impl +// +//============================================================================ + +bool SvDataPipe_Impl::remove(Page * pPage) +{ + if ( + pPage != m_pFirstPage || + m_pReadPage == m_pFirstPage || + ( + !m_aMarks.empty() && + *m_aMarks.begin() < m_pFirstPage->m_nOffset + m_nPageSize + ) + ) + { + return false; + } + + m_pFirstPage = m_pFirstPage->m_pNext; + + if (m_nPages <= m_nMinPages) + return true; + + pPage->m_pPrev->m_pNext = pPage->m_pNext; + pPage->m_pNext->m_pPrev = pPage->m_pPrev; + rtl_freeMemory(pPage); + --m_nPages; + + return true; +} + +//============================================================================ +SvDataPipe_Impl::~SvDataPipe_Impl() +{ + if (m_pFirstPage != 0) + for (Page * pPage = m_pFirstPage;;) + { + Page * pNext = pPage->m_pNext; + rtl_freeMemory(pPage); + if (pNext == m_pFirstPage) + break; + pPage = pNext; + } +} + +//============================================================================ +sal_uInt32 SvDataPipe_Impl::read() +{ + if (m_pReadBuffer == 0 || m_nReadBufferSize == 0 || m_pReadPage == 0) + return 0; + + sal_uInt32 nSize = m_nReadBufferSize; + sal_uInt32 nRemain = m_nReadBufferSize - m_nReadBufferFilled; + + m_pReadBuffer += m_nReadBufferFilled; + m_nReadBufferSize -= m_nReadBufferFilled; + m_nReadBufferFilled = 0; + + while (nRemain > 0) + { + sal_uInt32 nBlock = std::min(sal_uInt32(m_pReadPage->m_pEnd + - m_pReadPage->m_pRead), + nRemain); + rtl_copyMemory(m_pReadBuffer, m_pReadPage->m_pRead, nBlock); + m_pReadPage->m_pRead += nBlock; + m_pReadBuffer += nBlock; + m_nReadBufferSize -= nBlock; + m_nReadBufferFilled = 0; + nRemain -= nBlock; + + if (m_pReadPage == m_pWritePage) + break; + + if (m_pReadPage->m_pRead == m_pReadPage->m_pEnd) + { + Page * pRemove = m_pReadPage; + m_pReadPage = pRemove->m_pNext; + remove(pRemove); + } + } + + return nSize - nRemain; +} + +//============================================================================ +sal_uInt32 SvDataPipe_Impl::write(sal_Int8 const * pBuffer, sal_uInt32 nSize) +{ + if (nSize == 0) + return 0; + + if (m_pWritePage == 0) + { + m_pFirstPage + = static_cast< Page * >(rtl_allocateMemory(sizeof (Page) + + m_nPageSize + - 1)); + m_pFirstPage->m_pPrev = m_pFirstPage; + m_pFirstPage->m_pNext = m_pFirstPage; + m_pFirstPage->m_pStart = m_pFirstPage->m_aBuffer; + m_pFirstPage->m_pRead = m_pFirstPage->m_aBuffer; + m_pFirstPage->m_pEnd = m_pFirstPage->m_aBuffer; + m_pFirstPage->m_nOffset = 0; + m_pReadPage = m_pFirstPage; + m_pWritePage = m_pFirstPage; + ++m_nPages; + } + + sal_uInt32 nRemain = nSize; + + if (m_pReadBuffer != 0 && m_pReadPage == m_pWritePage + && m_pReadPage->m_pRead == m_pWritePage->m_pEnd) + { + sal_uInt32 nBlock = std::min(nRemain, + sal_uInt32(m_nReadBufferSize + - m_nReadBufferFilled)); + sal_uInt32 nPosition = m_pWritePage->m_nOffset + + (m_pWritePage->m_pEnd + - m_pWritePage->m_aBuffer); + if (!m_aMarks.empty()) + nBlock = *m_aMarks.begin() > nPosition ? + std::min(nBlock, sal_uInt32(*m_aMarks.begin() + - nPosition)) : + 0; + + if (nBlock > 0) + { + rtl_copyMemory(m_pReadBuffer + m_nReadBufferFilled, pBuffer, + nBlock); + m_nReadBufferFilled += nBlock; + nRemain -= nBlock; + + nPosition += nBlock; + m_pWritePage->m_nOffset = (nPosition / m_nPageSize) * m_nPageSize; + m_pWritePage->m_pStart = m_pWritePage->m_aBuffer + + nPosition % m_nPageSize; + m_pWritePage->m_pRead = m_pWritePage->m_pStart; + m_pWritePage->m_pEnd = m_pWritePage->m_pStart; + } + } + + if (nRemain > 0) + for (;;) + { + sal_uInt32 nBlock + = std::min(sal_uInt32(m_pWritePage->m_aBuffer + m_nPageSize + - m_pWritePage->m_pEnd), + nRemain); + rtl_copyMemory(m_pWritePage->m_pEnd, pBuffer, nBlock); + m_pWritePage->m_pEnd += nBlock; + pBuffer += nBlock; + nRemain -= nBlock; + + if (nRemain == 0) + break; + + if (m_pWritePage->m_pNext == m_pFirstPage) + { + if (m_nPages == m_nMaxPages) + break; + + Page * pNew + = static_cast< Page * >(rtl_allocateMemory( + sizeof (Page) + m_nPageSize + - 1)); + pNew->m_pPrev = m_pWritePage; + pNew->m_pNext = m_pWritePage->m_pNext; + + m_pWritePage->m_pNext->m_pPrev = pNew; + m_pWritePage->m_pNext = pNew; + ++m_nPages; + } + + m_pWritePage->m_pNext->m_nOffset = m_pWritePage->m_nOffset + + m_nPageSize; + m_pWritePage = m_pWritePage->m_pNext; + m_pWritePage->m_pStart = m_pWritePage->m_aBuffer; + m_pWritePage->m_pRead = m_pWritePage->m_aBuffer; + m_pWritePage->m_pEnd = m_pWritePage->m_aBuffer; + } + + return nSize - nRemain; +} + +//============================================================================ +bool SvDataPipe_Impl::addMark(sal_uInt32 nPosition) +{ + if (m_pFirstPage != 0 && m_pFirstPage->m_nOffset > nPosition) + return false; + m_aMarks.insert(nPosition); + return true; +} + +//============================================================================ +bool SvDataPipe_Impl::removeMark(sal_uInt32 nPosition) +{ + std::multiset< sal_uInt32 >::iterator t = m_aMarks.find(nPosition); + if (t == m_aMarks.end()) + return false; + m_aMarks.erase(t); + while (remove(m_pFirstPage)) ; + return true; +} + +//============================================================================ +SvDataPipe_Impl::SeekResult SvDataPipe_Impl::setReadPosition(sal_uInt32 + nPosition) +{ + if (m_pFirstPage == 0) + return nPosition == 0 ? SEEK_OK : SEEK_PAST_END; + + if (nPosition + <= m_pReadPage->m_nOffset + + (m_pReadPage->m_pRead - m_pReadPage->m_aBuffer)) + { + if (nPosition + < m_pFirstPage->m_nOffset + + (m_pFirstPage->m_pStart - m_pFirstPage->m_aBuffer)) + return SEEK_BEFORE_MARKED; + + while (nPosition < m_pReadPage->m_nOffset) + { + m_pReadPage->m_pRead = m_pReadPage->m_pStart; + m_pReadPage = m_pReadPage->m_pPrev; + } + } + else + { + if (nPosition + > m_pWritePage->m_nOffset + + (m_pWritePage->m_pEnd - m_pWritePage->m_aBuffer)) + return SEEK_PAST_END; + + while (m_pReadPage != m_pWritePage + && nPosition >= m_pReadPage->m_nOffset + m_nPageSize) + { + Page * pRemove = m_pReadPage; + m_pReadPage = pRemove->m_pNext; + remove(pRemove); + } + } + + m_pReadPage->m_pRead = m_pReadPage->m_aBuffer + + (nPosition - m_pReadPage->m_nOffset); + return SEEK_OK; +} + |