tdf#97597: Ensure that each parsing thread has its own buffer.

Change-Id: I93077f954a49b3922930e4fc86c80228be0f4dd2
Reviewed-on: https://gerrit.libreoffice.org/33069
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Kohei Yoshida <libreoffice@kohei.us>
This commit is contained in:
Kohei Yoshida 2017-01-13 20:47:46 -05:00 committed by Kohei Yoshida
parent efce216ca5
commit 4ae705d02d
8 changed files with 166 additions and 26 deletions

View File

@ -317,17 +317,28 @@ uno::Reference< embed::XStorage > OStorageHelper::GetStorageOfFormatFromInputStr
const OUString& aFormat,
const uno::Reference < io::XInputStream >& xStream,
const uno::Reference< uno::XComponentContext >& rxContext,
bool bRepairStorage )
bool bRepairStorage, bool bUseBufferedStream )
throw ( uno::Exception )
{
uno::Sequence< beans::PropertyValue > aProps( 1 );
aProps[0].Name = "StorageFormat";
aProps[0].Value <<= aFormat;
sal_Int32 nPos = 0;
aProps[nPos].Name = "StorageFormat";
aProps[nPos].Value <<= aFormat;
++nPos;
if ( bRepairStorage )
{
aProps.realloc( 2 );
aProps[1].Name = "RepairPackage";
aProps[1].Value <<= bRepairStorage;
aProps.realloc(nPos+1);
aProps[nPos].Name = "RepairPackage";
aProps[nPos].Value <<= bRepairStorage;
++nPos;
}
if (bUseBufferedStream)
{
aProps.realloc(nPos+1);
aProps[nPos].Name = "UseBufferedStream";
aProps[nPos].Value <<= bUseBufferedStream;
++nPos;
}
uno::Sequence< uno::Any > aArgs( 3 );
@ -349,17 +360,28 @@ uno::Reference< embed::XStorage > OStorageHelper::GetStorageOfFormatFromStream(
const uno::Reference < io::XStream >& xStream,
sal_Int32 nStorageMode,
const uno::Reference< uno::XComponentContext >& rxContext,
bool bRepairStorage )
bool bRepairStorage, bool bUseBufferedStream )
throw ( uno::Exception )
{
uno::Sequence< beans::PropertyValue > aProps( 1 );
aProps[0].Name = "StorageFormat";
aProps[0].Value <<= aFormat;
sal_Int32 nPos = 0;
aProps[nPos].Name = "StorageFormat";
aProps[nPos].Value <<= aFormat;
++nPos;
if ( bRepairStorage )
{
aProps.realloc( 2 );
aProps[1].Name = "RepairPackage";
aProps[1].Value <<= bRepairStorage;
aProps.realloc(nPos+1);
aProps[nPos].Name = "RepairPackage";
aProps[nPos].Value <<= bRepairStorage;
++nPos;
}
if (bUseBufferedStream)
{
aProps.realloc(nPos+1);
aProps[nPos].Name = "UseBufferedStream";
aProps[nPos].Value <<= bUseBufferedStream;
++nPos;
}
uno::Sequence< uno::Any > aArgs( 3 );

View File

@ -154,7 +154,8 @@ public:
const css::uno::Reference < css::io::XInputStream >& xStream,
const css::uno::Reference< css::uno::XComponentContext >& rxContext
= css::uno::Reference< css::uno::XComponentContext >(),
bool bRepairStorage = false )
bool bRepairStorage = false,
bool bUseBufferedStream = false )
throw ( css::uno::Exception );
static css::uno::Reference< css::embed::XStorage >
@ -164,7 +165,8 @@ public:
sal_Int32 nStorageMode = css::embed::ElementModes::READWRITE,
const css::uno::Reference< css::uno::XComponentContext >& rxContext
= css::uno::Reference< css::uno::XComponentContext >(),
bool bRepairStorage = false )
bool bRepairStorage = false,
bool bUseBufferedStream = false )
throw ( css::uno::Exception );
static css::uno::Sequence< css::beans::NamedValue >

View File

@ -58,7 +58,7 @@ ZipStorage::ZipStorage( const Reference< XComponentContext >& rxContext, const R
implementation of relations handling.
*/
mxStorage = ::comphelper::OStorageHelper::GetStorageOfFormatFromInputStream(
ZIP_STORAGE_FORMAT_STRING, rxInStream, rxContext );
ZIP_STORAGE_FORMAT_STRING, rxInStream, rxContext, false, true);
}
catch (Exception const& e)
{
@ -76,7 +76,7 @@ ZipStorage::ZipStorage( const Reference< XComponentContext >& rxContext, const R
{
const sal_Int32 nOpenMode = ElementModes::READWRITE | ElementModes::TRUNCATE;
mxStorage = ::comphelper::OStorageHelper::GetStorageOfFormatFromStream(
OFOPXML_STORAGE_FORMAT_STRING, rxStream, nOpenMode, rxContext, true );
OFOPXML_STORAGE_FORMAT_STRING, rxStream, nOpenMode, rxContext, true, true);
}
catch (Exception const& e)
{

View File

@ -64,9 +64,10 @@ class ZipFile
const css::uno::Reference < css::uno::XComponentContext > m_xContext;
bool bRecoveryMode;
bool mbUseBufferedStream;
// aMediaType parameter is used only for raw stream header creation
css::uno::Reference < css::io::XInputStream > createUnbufferedStream(
css::uno::Reference < css::io::XInputStream > createStreamForZipEntry(
const rtl::Reference<SotMutexHolder>& aMutexHolder,
ZipEntry & rEntry,
const ::rtl::Reference < EncryptionData > &rData,
@ -102,6 +103,8 @@ public:
EntryHash& GetEntryHash() { return aEntries; }
void setUseBufferedStream( bool b );
void setInputStream ( const css::uno::Reference < css::io::XInputStream >& xNewStream );
css::uno::Reference< css::io::XInputStream > getRawData(
ZipEntry& rEntry,

View File

@ -193,8 +193,8 @@ uno::Reference< uno::XInterface > SAL_CALL OStorageFactory::createInstanceWithAr
if ( aDescr[nInd].Name == "InteractionHandler"
|| aDescr[nInd].Name == "Password"
|| aDescr[nInd].Name == "RepairPackage"
|| aDescr[nInd].Name == "StatusIndicator" )
// || aDescr[nInd].Name == "Unpacked" ) // TODO:
|| aDescr[nInd].Name == "StatusIndicator"
|| aDescr[nInd].Name == "UseBufferedStream" )
{
aPropsToSet.realloc( ++nNumArgs );
aPropsToSet[nNumArgs-1].Name = aDescr[nInd].Name;

View File

@ -467,7 +467,8 @@ void OStorage_Impl::OpenOwnPackage()
for ( sal_Int32 aInd = 0; aInd < m_xProperties.getLength(); aInd++ )
{
if ( m_xProperties[aInd].Name == "RepairPackage"
|| m_xProperties[aInd].Name == "ProgressHandler" )
|| m_xProperties[aInd].Name == "ProgressHandler"
|| m_xProperties[aInd].Name == "UseBufferedStream" )
{
beans::NamedValue aNamedValue( m_xProperties[aInd].Name,
m_xProperties[aInd].Value );

View File

@ -74,6 +74,7 @@ ZipFile::ZipFile( uno::Reference < XInputStream > &xInput, const uno::Reference
, xStream(xInput)
, m_xContext ( rxContext )
, bRecoveryMode( false )
, mbUseBufferedStream(false)
{
if (bInitialise)
{
@ -91,6 +92,7 @@ ZipFile::ZipFile( uno::Reference < XInputStream > &xInput, const uno::Reference
, xStream(xInput)
, m_xContext ( rxContext )
, bRecoveryMode( bForceRecovery )
, mbUseBufferedStream(false)
{
if (bInitialise)
{
@ -111,6 +113,11 @@ ZipFile::~ZipFile()
aEntries.clear();
}
void ZipFile::setUseBufferedStream( bool b )
{
mbUseBufferedStream = b;
}
void ZipFile::setInputStream ( const uno::Reference < XInputStream >& xNewStream )
{
::osl::MutexGuard aGuard( m_aMutex );
@ -504,7 +511,99 @@ bool ZipFile::hasValidPassword ( ZipEntry & rEntry, const ::rtl::Reference< Encr
return bRet;
}
uno::Reference< XInputStream > ZipFile::createUnbufferedStream(
namespace {
class XBufferedStream : public cppu::WeakImplHelper<css::io::XInputStream>
{
std::vector<sal_Int8> maBytes;
size_t mnPos;
size_t remainingSize() const
{
return maBytes.size() - mnPos;
}
bool hasBytes() const
{
return mnPos < maBytes.size();
}
public:
XBufferedStream( const uno::Reference<XInputStream>& xSrcStream ) : mnPos(0)
{
const sal_Int32 nBufSize = 8192;
sal_Int32 nRemaining = xSrcStream->available();
maBytes.reserve(nRemaining);
uno::Sequence<sal_Int8> aBuf(nBufSize);
auto readAndCopy = [&]( sal_Int32 nReadSize ) -> sal_Int32
{
sal_Int32 nBytes = xSrcStream->readBytes(aBuf, nReadSize);
const sal_Int8* p = aBuf.getArray();
const sal_Int8* pEnd = p + nBytes;
std::copy(p, pEnd, std::back_inserter(maBytes));
return nBytes;
};
while (nRemaining > nBufSize)
nRemaining -= readAndCopy(nBufSize);
if (nRemaining)
readAndCopy(nRemaining);
}
virtual sal_Int32 SAL_CALL readBytes( uno::Sequence<sal_Int8>& rData, sal_Int32 nBytesToRead )
throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception) override
{
if (!hasBytes())
return 0;
sal_Int32 nReadSize = std::min<sal_Int32>(nBytesToRead, remainingSize());
rData.realloc(nReadSize);
std::vector<sal_Int8>::const_iterator it = maBytes.cbegin();
std::advance(it, mnPos);
for (sal_Int32 i = 0; i < nReadSize; ++i, ++it)
rData[i] = *it;
mnPos += nReadSize;
return nReadSize;
}
virtual sal_Int32 SAL_CALL readSomeBytes( ::css::uno::Sequence<sal_Int8>& rData, sal_Int32 nMaxBytesToRead )
throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception) override
{
return readBytes(rData, nMaxBytesToRead);
}
virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip )
throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception) override
{
if (!hasBytes())
return;
mnPos += nBytesToSkip;
}
virtual sal_Int32 SAL_CALL available()
throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception) override
{
if (!hasBytes())
return 0;
return remainingSize();
}
virtual void SAL_CALL closeInput()
throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception) override
{
}
};
}
uno::Reference< XInputStream > ZipFile::createStreamForZipEntry(
const rtl::Reference<SotMutexHolder>& aMutexHolder,
ZipEntry & rEntry,
const ::rtl::Reference< EncryptionData > &rData,
@ -514,7 +613,14 @@ uno::Reference< XInputStream > ZipFile::createUnbufferedStream(
{
::osl::MutexGuard aGuard( m_aMutex );
return new XUnbufferedStream ( m_xContext, aMutexHolder, rEntry, xStream, rData, nStreamMode, bIsEncrypted, aMediaType, bRecoveryMode );
uno::Reference<io::XInputStream> xSrcStream = new XUnbufferedStream(
m_xContext, aMutexHolder, rEntry, xStream, rData, nStreamMode, bIsEncrypted, aMediaType, bRecoveryMode);
if (!mbUseBufferedStream)
return xSrcStream;
uno::Reference<io::XInputStream> xBufStream(new XBufferedStream(xSrcStream));
return xBufStream;
}
std::unique_ptr<ZipEnumeration> ZipFile::entries()
@ -542,7 +648,7 @@ uno::Reference< XInputStream > ZipFile::getInputStream( ZipEntry& rEntry,
if ( bIsEncrypted && rData.is() && rData->m_aDigest.getLength() )
bNeedRawStream = !hasValidPassword ( rEntry, rData );
return createUnbufferedStream ( aMutexHolder,
return createStreamForZipEntry ( aMutexHolder,
rEntry,
rData,
bNeedRawStream ? UNBUFF_STREAM_RAW : UNBUFF_STREAM_DATA,
@ -578,7 +684,7 @@ uno::Reference< XInputStream > ZipFile::getDataStream( ZipEntry& rEntry,
else
bNeedRawStream = ( rEntry.nMethod == STORED );
return createUnbufferedStream ( aMutexHolder,
return createStreamForZipEntry ( aMutexHolder,
rEntry,
rData,
bNeedRawStream ? UNBUFF_STREAM_RAW : UNBUFF_STREAM_DATA,
@ -595,7 +701,7 @@ uno::Reference< XInputStream > ZipFile::getRawData( ZipEntry& rEntry,
if ( rEntry.nOffset <= 0 )
readLOC( rEntry );
return createUnbufferedStream ( aMutexHolder, rEntry, rData, UNBUFF_STREAM_RAW, bIsEncrypted );
return createStreamForZipEntry ( aMutexHolder, rEntry, rData, UNBUFF_STREAM_RAW, bIsEncrypted );
}
uno::Reference< XInputStream > ZipFile::getWrappedRawStream(
@ -612,7 +718,7 @@ uno::Reference< XInputStream > ZipFile::getWrappedRawStream(
if ( rEntry.nOffset <= 0 )
readLOC( rEntry );
return createUnbufferedStream ( aMutexHolder, rEntry, rData, UNBUFF_STREAM_WRAPPEDRAW, true, aMediaType );
return createStreamForZipEntry ( aMutexHolder, rEntry, rData, UNBUFF_STREAM_WRAPPEDRAW, true, aMediaType );
}
bool ZipFile::readLOC( ZipEntry &rEntry )

View File

@ -563,6 +563,7 @@ void SAL_CALL ZipPackage::initialize( const uno::Sequence< Any >& aArguments )
if ( aArguments.getLength() )
{
bool bHaveZipFile = true;
bool bUseBufferedStream = false;
for( int ind = 0; ind < aArguments.getLength(); ind++ )
{
@ -690,6 +691,10 @@ void SAL_CALL ZipPackage::initialize( const uno::Sequence< Any >& aArguments )
aNamedValue.Value >>= m_bAllowRemoveOnInsert;
m_xRootFolder->setRemoveOnInsertMode_Impl( m_bAllowRemoveOnInsert );
}
else if (aNamedValue.Name == "UseBufferedStream")
{
aNamedValue.Value >>= bUseBufferedStream;
}
// for now the progress handler is not used, probably it will never be
// if ( aNamedValue.Name == "ProgressHandler" )
@ -733,6 +738,7 @@ void SAL_CALL ZipPackage::initialize( const uno::Sequence< Any >& aArguments )
try
{
m_pZipFile = o3tl::make_unique<ZipFile>(m_xContentStream, m_xContext, true, m_bForceRecovery);
m_pZipFile->setUseBufferedStream(bUseBufferedStream);
getZipFileContents();
}
catch ( IOException & e )