tdf#63130 reduce large memory copies when reading from BinaryDataContainer
rather than writing a bunch more code, extract the common part from
comphelper::SequenceInputStream into a new base class
Change-Id: I0d3561e3ca2e748b904128e3b5955e27196d7170
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151943
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
diff --git a/comphelper/source/streaming/seqstream.cxx b/comphelper/source/streaming/seqstream.cxx
index 9626484..49eebc1 100644
--- a/comphelper/source/streaming/seqstream.cxx
+++ b/comphelper/source/streaming/seqstream.cxx
@@ -36,26 +36,27 @@ using namespace ::osl;
SequenceInputStream::SequenceInputStream(
css::uno::Sequence<sal_Int8> const & rData)
: m_aData(rData)
MemoryInputStream::MemoryInputStream(
const sal_Int8* pData, sal_Int32 nDataLength)
: m_pMemoryData(pData)
, m_nMemoryDataLength(nDataLength)
, m_nPos(0)
{
}
// checks if closed, returns available size, not mutex-protected
inline sal_Int32 SequenceInputStream::avail()
inline sal_Int32 MemoryInputStream::avail()
{
if (m_nPos == -1)
throw NotConnectedException(OUString(), *this);
return m_aData.getLength() - m_nPos;
return m_nMemoryDataLength - m_nPos;
}
// css::io::XInputStream
sal_Int32 SAL_CALL SequenceInputStream::readBytes( Sequence<sal_Int8>& aData, sal_Int32 nBytesToRead )
sal_Int32 SAL_CALL MemoryInputStream::readBytes( Sequence<sal_Int8>& aData, sal_Int32 nBytesToRead )
{
if (nBytesToRead < 0)
throw BufferSizeExceededException(OUString(),*this);
@@ -68,13 +69,13 @@ sal_Int32 SAL_CALL SequenceInputStream::readBytes( Sequence<sal_Int8>& aData, sa
nBytesToRead = nAvail;
aData.realloc(nBytesToRead);
memcpy(aData.getArray(), m_aData.getConstArray() + m_nPos, nBytesToRead);
memcpy(aData.getArray(), m_pMemoryData + m_nPos, nBytesToRead);
m_nPos += nBytesToRead;
return nBytesToRead;
}
sal_Int32 SequenceInputStream::readSomeBytes( sal_Int8* pData, sal_Int32 nBytesToRead )
sal_Int32 MemoryInputStream::readSomeBytes( sal_Int8* pData, sal_Int32 nBytesToRead )
{
if (nBytesToRead < 0)
throw BufferSizeExceededException(OUString(),*this);
@@ -86,20 +87,20 @@ sal_Int32 SequenceInputStream::readSomeBytes( sal_Int8* pData, sal_Int32 nBytesT
if (nAvail < nBytesToRead)
nBytesToRead = nAvail;
memcpy(pData, m_aData.getConstArray() + m_nPos, nBytesToRead);
memcpy(pData, m_pMemoryData + m_nPos, nBytesToRead);
m_nPos += nBytesToRead;
return nBytesToRead;
}
sal_Int32 SAL_CALL SequenceInputStream::readSomeBytes( Sequence<sal_Int8>& aData, sal_Int32 nMaxBytesToRead )
sal_Int32 SAL_CALL MemoryInputStream::readSomeBytes( Sequence<sal_Int8>& aData, sal_Int32 nMaxBytesToRead )
{
// all data is available at once
return readBytes(aData, nMaxBytesToRead);
}
void SAL_CALL SequenceInputStream::skipBytes( sal_Int32 nBytesToSkip )
void SAL_CALL MemoryInputStream::skipBytes( sal_Int32 nBytesToSkip )
{
if (nBytesToSkip < 0)
throw BufferSizeExceededException(OUString(),*this);
@@ -115,7 +116,7 @@ void SAL_CALL SequenceInputStream::skipBytes( sal_Int32 nBytesToSkip )
}
sal_Int32 SAL_CALL SequenceInputStream::available( )
sal_Int32 SAL_CALL MemoryInputStream::available( )
{
std::scoped_lock aGuard( m_aMutex );
@@ -123,7 +124,7 @@ sal_Int32 SAL_CALL SequenceInputStream::available( )
}
void SAL_CALL SequenceInputStream::closeInput( )
void SAL_CALL MemoryInputStream::closeInput( )
{
std::scoped_lock aGuard( m_aMutex );
@@ -133,24 +134,32 @@ void SAL_CALL SequenceInputStream::closeInput( )
m_nPos = -1;
}
void SAL_CALL SequenceInputStream::seek( sal_Int64 location )
void SAL_CALL MemoryInputStream::seek( sal_Int64 location )
{
if ( location > m_aData.getLength() || location < 0 || location > SAL_MAX_INT32 )
if ( location > m_nMemoryDataLength || location < 0 || location > SAL_MAX_INT32 )
throw IllegalArgumentException("bad location", static_cast<cppu::OWeakObject*>(this), 1);
std::scoped_lock aGuard( m_aMutex );
m_nPos = static_cast<sal_Int32>(location);
}
sal_Int64 SAL_CALL SequenceInputStream::getPosition()
sal_Int64 SAL_CALL MemoryInputStream::getPosition()
{
std::scoped_lock aGuard( m_aMutex );
return m_nPos;
}
sal_Int64 SAL_CALL SequenceInputStream::getLength( )
sal_Int64 SAL_CALL MemoryInputStream::getLength( )
{
std::scoped_lock aGuard( m_aMutex );
return m_aData.getLength();
return m_nMemoryDataLength;
}
SequenceInputStream::SequenceInputStream(
css::uno::Sequence<sal_Int8> const & rData)
: MemoryInputStream(rData.getConstArray(), rData.getLength())
, m_aData(rData)
{
}
diff --git a/include/comphelper/seqstream.hxx b/include/comphelper/seqstream.hxx
index 1f1db11..1fd695b 100644
--- a/include/comphelper/seqstream.hxx
+++ b/include/comphelper/seqstream.hxx
@@ -33,21 +33,18 @@
namespace comphelper
{
// SequenceInputStream
// stream for reading data from a sequence of bytes
class COMPHELPER_DLLPUBLIC SequenceInputStream final
/** Base class for wrappers around memory data that want to be exposed as an XInputStream */
class COMPHELPER_DLLPUBLIC MemoryInputStream
: public ::cppu::WeakImplHelper< css::io::XInputStream, css::io::XSeekable >,
public comphelper::ByteReader
{
std::mutex m_aMutex;
css::uno::Sequence<sal_Int8> const m_aData;
const sal_Int8* m_pMemoryData;
sal_Int32 m_nMemoryDataLength;
sal_Int32 m_nPos;
public:
SequenceInputStream(css::uno::Sequence<sal_Int8> const & rData);
MemoryInputStream(const sal_Int8* pData, sal_Int32 nDataLength);
// css::io::XInputStream
virtual sal_Int32 SAL_CALL readBytes( css::uno::Sequence<sal_Int8>& aData, sal_Int32 nBytesToRead ) override;
@@ -71,6 +68,17 @@ private:
sal_Int32 avail();
};
// Stream for reading data from a sequence of bytes
class COMPHELPER_DLLPUBLIC SequenceInputStream final
: public MemoryInputStream
{
css::uno::Sequence<sal_Int8> const m_aData;
public:
SequenceInputStream(css::uno::Sequence<sal_Int8> const & rData);
};
// don't export to avoid duplicate WeakImplHelper definitions with MSVC
class SAL_DLLPUBLIC_TEMPLATE OSequenceOutputStream_Base
: public ::cppu::WeakImplHelper< css::io::XOutputStream >
diff --git a/include/vcl/BinaryDataContainer.hxx b/include/vcl/BinaryDataContainer.hxx
index f6f07f0..72bd852 100644
--- a/include/vcl/BinaryDataContainer.hxx
+++ b/include/vcl/BinaryDataContainer.hxx
@@ -13,6 +13,7 @@
#include <sal/config.h>
#include <com/sun/star/uno/Sequence.hxx>
#include <com/sun/star/io/XInputStream.hpp>
#include <unotools/tempfile.hxx>
#include <tools/stream.hxx>
#include <vcl/dllapi.h>
@@ -53,6 +54,9 @@ public:
// Returns the data as a readonly stream open for reading
std::shared_ptr<SvStream> getAsStream();
// Returns the data as a readonly stream open for reading
css::uno::Reference<css::io::XInputStream> getAsXInputStream();
/// writes the contents to the given stream
std::size_t writeToStream(SvStream& rStream) const;
diff --git a/vcl/source/gdi/vectorgraphicdata.cxx b/vcl/source/gdi/vectorgraphicdata.cxx
index 979fd4f..7dc5107 100644
--- a/vcl/source/gdi/vectorgraphicdata.cxx
+++ b/vcl/source/gdi/vectorgraphicdata.cxx
@@ -196,8 +196,7 @@ void VectorGraphicData::ensureSequenceAndRange()
{
case VectorGraphicDataType::Svg:
{
css::uno::Sequence<sal_Int8> aDataSequence = maDataContainer.getCopyAsByteSequence();
const uno::Reference<io::XInputStream> xInputStream(new comphelper::SequenceInputStream(aDataSequence));
const uno::Reference<io::XInputStream> xInputStream = maDataContainer.getAsXInputStream();
const uno::Reference< graphic::XSvgParser > xSvgParser = graphic::SvgTools::create(xContext);
@@ -211,8 +210,7 @@ void VectorGraphicData::ensureSequenceAndRange()
{
const uno::Reference< graphic::XEmfParser > xEmfParser = graphic::EmfTools::create(xContext);
css::uno::Sequence<sal_Int8> aDataSequence = maDataContainer.getCopyAsByteSequence();
const uno::Reference<io::XInputStream> xInputStream(new comphelper::SequenceInputStream(aDataSequence));
const uno::Reference<io::XInputStream> xInputStream = maDataContainer.getAsXInputStream();
if (xInputStream.is())
{
diff --git a/vcl/source/graphic/BinaryDataContainer.cxx b/vcl/source/graphic/BinaryDataContainer.cxx
index f395497f..83cacb4 100644
--- a/vcl/source/graphic/BinaryDataContainer.cxx
+++ b/vcl/source/graphic/BinaryDataContainer.cxx
@@ -12,6 +12,7 @@
#include <o3tl/hash_combine.hxx>
#include <unotools/tempfile.hxx>
#include <comphelper/lok.hxx>
#include <comphelper/seqstream.hxx>
#include <sal/log.hxx>
struct BinaryDataContainer::Impl
@@ -115,6 +116,19 @@ public:
{
}
};
class ReferencedXInputStream : public comphelper::MemoryInputStream
{
std::shared_ptr<std::vector<sal_uInt8>> mpData;
public:
ReferencedXInputStream(const std::shared_ptr<std::vector<sal_uInt8>>& pData)
: comphelper::MemoryInputStream(reinterpret_cast<const sal_Int8*>(pData->data()),
pData->size())
, mpData(pData)
{
}
};
}
std::shared_ptr<SvStream> BinaryDataContainer::getAsStream()
@@ -123,6 +137,12 @@ std::shared_ptr<SvStream> BinaryDataContainer::getAsStream()
return std::make_shared<ReferencedMemoryStream>(mpImpl->mpData);
}
css::uno::Reference<css::io::XInputStream> BinaryDataContainer::getAsXInputStream()
{
ensureSwappedIn(); // TODO: transfer in streamed chunks
return new ReferencedXInputStream(mpImpl->mpData);
}
std::size_t BinaryDataContainer::writeToStream(SvStream& rStream) const
{
ensureSwappedIn(); // TODO: transfer in streamed chunks