diff options
author | Kohei Yoshida <kohei.yoshida@collabora.com> | 2017-01-13 20:47:46 -0500 |
---|---|---|
committer | Kohei Yoshida <libreoffice@kohei.us> | 2017-01-14 17:30:30 +0000 |
commit | 4ae705d02df0ddf75b97d0e94add6994626f487e (patch) | |
tree | 019b0b47b2d777a83c4996ffec2022384ed72755 /package | |
parent | efce216ca5d2b852c9fccc52ee68d1e27279d900 (diff) |
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>
Diffstat (limited to 'package')
-rw-r--r-- | package/inc/ZipFile.hxx | 5 | ||||
-rw-r--r-- | package/source/xstor/xfactory.cxx | 4 | ||||
-rw-r--r-- | package/source/xstor/xstorage.cxx | 3 | ||||
-rw-r--r-- | package/source/zipapi/ZipFile.cxx | 118 | ||||
-rw-r--r-- | package/source/zippackage/ZipPackage.cxx | 6 |
5 files changed, 126 insertions, 10 deletions
diff --git a/package/inc/ZipFile.hxx b/package/inc/ZipFile.hxx index 9d1a6da0d2bc..e84ace2abd11 100644 --- a/package/inc/ZipFile.hxx +++ b/package/inc/ZipFile.hxx @@ -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, diff --git a/package/source/xstor/xfactory.cxx b/package/source/xstor/xfactory.cxx index 95bb21a84622..d5031b4dbc03 100644 --- a/package/source/xstor/xfactory.cxx +++ b/package/source/xstor/xfactory.cxx @@ -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; diff --git a/package/source/xstor/xstorage.cxx b/package/source/xstor/xstorage.cxx index 29155de03ebb..68f47a89db85 100644 --- a/package/source/xstor/xstorage.cxx +++ b/package/source/xstor/xstorage.cxx @@ -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 ); diff --git a/package/source/zipapi/ZipFile.cxx b/package/source/zipapi/ZipFile.cxx index 08d862aad637..0f436aba67a0 100644 --- a/package/source/zipapi/ZipFile.cxx +++ b/package/source/zipapi/ZipFile.cxx @@ -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 ) diff --git a/package/source/zippackage/ZipPackage.cxx b/package/source/zippackage/ZipPackage.cxx index cb2e618a62ee..83b3a82c37c1 100644 --- a/package/source/zippackage/ZipPackage.cxx +++ b/package/source/zippackage/ZipPackage.cxx @@ -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 ) |