From eb1653ca7f32523d071624bc9830a240bf965810 Mon Sep 17 00:00:00 2001 From: David Tardon Date: Mon, 13 Jan 2014 12:27:38 +0100 Subject: prepare WPXSvInputStream for librevenge Change-Id: Iefcfe00c2febbb00bcf093acf252291409929f1a --- writerperfect/source/common/WPXSvStream.cxx | 436 +++++++++++++++++++++++----- writerperfect/source/common/WPXSvStream.hxx | 12 +- 2 files changed, 371 insertions(+), 77 deletions(-) diff --git a/writerperfect/source/common/WPXSvStream.cxx b/writerperfect/source/common/WPXSvStream.cxx index 86e835b0dc23..42b660a396b8 100644 --- a/writerperfect/source/common/WPXSvStream.cxx +++ b/writerperfect/source/common/WPXSvStream.cxx @@ -8,21 +8,51 @@ */ #include "WPXSvStream.hxx" + +#include #include #include #include + #include #include +#include +#include + using namespace ::com::sun::star::uno; using namespace ::com::sun::star::io; namespace { -static void splitPath( std::vector &rElems, const OUString &rPath ) + +class PositionHolder +{ + // disable copying + PositionHolder(const PositionHolder &); + PositionHolder &operator=(const PositionHolder &); + +public: + explicit PositionHolder(const Reference &rxSeekable); + ~PositionHolder(); + +private: + const Reference mxSeekable; + const sal_uInt64 mnPosition; +}; + +PositionHolder::PositionHolder(const Reference &rxSeekable) + : mxSeekable(rxSeekable) + , mnPosition(rxSeekable->getPosition()) +{ +} + +PositionHolder::~PositionHolder() try +{ + mxSeekable->seek(mnPosition); +} +catch (...) { - for (sal_Int32 i = 0; i >= 0;) - rElems.push_back( rPath.getToken( 0, '/', i ) ); } } // anonymous namespace @@ -37,6 +67,154 @@ typedef struct SotStorageStreamRef ref; } SotStorageStreamRefWrapper; +namespace +{ + +const rtl::OUString concatPath(const rtl::OUString &lhs, const rtl::OUString &rhs) +{ + if (lhs.isEmpty()) + return rhs; + return lhs + "/" + rhs; +} + +struct StreamData +{ + explicit StreamData(const rtl::OString &rName); + + SotStorageStreamRefWrapper stream; + rtl::OString name; +}; + +typedef boost::unordered_map NameMap_t; +typedef boost::unordered_map OLEStorageMap_t; + +struct OLEStorageImpl +{ + OLEStorageImpl(); + + void initialize(SvStream *pStream); + + SotStorageStreamRef getStream(const rtl::OUString &rPath); + SotStorageStreamRef getStream(std::size_t nId); + +private: + void traverse(const SotStorageRef &rStorage, const rtl::OUString &rPath); + + SotStorageStreamRef createStream(const rtl::OUString &rPath); + +public: + boost::scoped_ptr mpStream; + SotStorageRefWrapper mxRootStorage; + OLEStorageMap_t maStorageMap; + ::std::vector< StreamData > maStreams; + NameMap_t maNameMap; + bool mbInitialized; +}; + +StreamData::StreamData(const rtl::OString &rName) + : stream() + , name(rName) +{ +} + +OLEStorageImpl::OLEStorageImpl() + : mpStream() + , mxRootStorage() + , maStorageMap() + , maStreams() + , maNameMap() + , mbInitialized(false) +{ +} + +void OLEStorageImpl::initialize(SvStream *const pStream) +{ + if (!pStream) + return; + + mpStream.reset(pStream); + mxRootStorage.ref = new SotStorage( pStream, sal_True ); + + traverse(mxRootStorage.ref, ""); + + mbInitialized = true; +} + +SotStorageStreamRef OLEStorageImpl::getStream(const rtl::OUString &rPath) +{ + NameMap_t::iterator aIt = maNameMap.find(rPath); + + // For the while don't return stream in this situation. + // Later, given how libcdr's zip stream implementation behaves, + // return the first stream in the storage if there is one. + if (maNameMap.end() == aIt) + return SotStorageStreamRef(); + + if (!maStreams[aIt->second].stream.ref.Is()) + maStreams[aIt->second].stream.ref = createStream(rPath); + + return maStreams[aIt->second].stream.ref; +} + +SotStorageStreamRef OLEStorageImpl::getStream(const std::size_t nId) +{ + if (!maStreams[nId].stream.ref.Is()) + maStreams[nId].stream.ref = createStream(rtl::OStringToOUString(maStreams[nId].name, RTL_TEXTENCODING_UTF8)); + + return maStreams[nId].stream.ref; +} + +void OLEStorageImpl::traverse(const SotStorageRef &rStorage, const rtl::OUString &rPath) +{ + SvStorageInfoList infos; + + rStorage->FillInfoList(&infos); + + for (SvStorageInfoList::const_iterator aIt = infos.begin(); infos.end() != aIt; ++aIt) + { + if (aIt->IsStream()) + { + maStreams.push_back(StreamData(rtl::OUStringToOString(aIt->GetName(), RTL_TEXTENCODING_UTF8))); + maNameMap[concatPath(rPath, aIt->GetName())] = maStreams.size() - 1; + } + else if (aIt->IsStorage()) + { + const rtl::OUString aPath = concatPath(rPath, aIt->GetName()); + SotStorageRefWrapper xStorage; + xStorage.ref = rStorage->OpenSotStorage(aIt->GetName(), STREAM_STD_READ); + maStorageMap[aPath] = xStorage; + + // deep-first traversal + traverse(xStorage.ref, aPath); + } + else + { + assert(0); + } + } +} + +SotStorageStreamRef OLEStorageImpl::createStream(const rtl::OUString &rPath) +{ + const sal_Int32 nDelim = rPath.lastIndexOf(sal_Unicode('/')); + + if (-1 == nDelim) + return mxRootStorage.ref->OpenSotStream(rPath, STREAM_STD_READ); + + const rtl::OUString aDir = rPath.copy(0, nDelim); + const rtl::OUString aName = rPath.copy(nDelim + 1); + + const OLEStorageMap_t::const_iterator aIt = maStorageMap.find(aDir); + + // We can only get there for paths that are present in the OLE. + // Which means the storage must exist. + assert(maStorageMap.end() != aIt); + + return aIt->second.ref->OpenSotStream(aName, STREAM_STD_READ); +} + +} + class WPXSvInputStreamImpl { public : @@ -44,22 +222,32 @@ public : ::com::sun::star::io::XInputStream > xStream ); ~WPXSvInputStreamImpl(); - bool isOLEStream(); - WPXInputStream * getDocumentOLEStream(const char *name); + bool isStructured(); + unsigned subStreamCount(); + const char * subStreamName(unsigned id); + bool existsSubStream(const char *name); + WPXInputStream * getSubStreamByName(const char *name); + WPXInputStream * getSubStreamById(unsigned id); const unsigned char *read(unsigned long numBytes, unsigned long &numBytesRead); int seek(long offset); long tell(); - bool atEOS(); + bool isEnd(); + void invalidateReadBuffer(); + private: - ::std::vector< SotStorageRefWrapper > mxChildrenStorages; - ::std::vector< SotStorageStreamRefWrapper > mxChildrenStreams; - ::com::sun::star::uno::Reference< - ::com::sun::star::io::XInputStream > mxStream; - ::com::sun::star::uno::Reference< - ::com::sun::star::io::XSeekable > mxSeekable; + bool isOLE(); + void ensureOLEIsInitialized(); + + WPXInputStream *createWPXStream(const SotStorageStreamRef &rxStorage); + +private: + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > mxStream; + ::com::sun::star::uno::Reference< ::com::sun::star::io::XSeekable > mxSeekable; ::com::sun::star::uno::Sequence< sal_Int8 > maData; + boost::scoped_ptr< OLEStorageImpl > mpOLEStorage; + bool mbCheckedOLE; public: sal_Int64 mnLength; unsigned char *mpReadBuffer; @@ -68,8 +256,6 @@ public: }; WPXSvInputStreamImpl::WPXSvInputStreamImpl( Reference< XInputStream > xStream ) : - mxChildrenStorages(), - mxChildrenStreams(), mxStream(xStream), mxSeekable(xStream, UNO_QUERY), maData(0), @@ -109,7 +295,7 @@ const unsigned char *WPXSvInputStreamImpl::read(unsigned long numBytes, unsigned { numBytesRead = 0; - if (numBytes == 0 || atEOS()) + if (numBytes == 0 || isEnd()) return 0; numBytesRead = mxStream->readSomeBytes (maData, numBytes); @@ -153,99 +339,127 @@ int WPXSvInputStreamImpl::seek(long offset) } } -bool WPXSvInputStreamImpl::atEOS() +bool WPXSvInputStreamImpl::isEnd() { if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is()) return true; return (mxSeekable->getPosition() >= mnLength); } -bool WPXSvInputStreamImpl::isOLEStream() +bool WPXSvInputStreamImpl::isStructured() { if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is()) return false; - sal_Int64 tmpPosition = mxSeekable->getPosition(); + PositionHolder pos(mxSeekable); mxSeekable->seek(0); - SvStream *pStream = utl::UcbStreamHelper::CreateStream( mxStream ); - bool bAns = pStream && SotStorage::IsOLEStorage( pStream ); - if (pStream) - delete pStream; - - mxSeekable->seek(tmpPosition); - - return bAns; + return isOLE(); } -WPXInputStream *WPXSvInputStreamImpl::getDocumentOLEStream(const char *name) +unsigned WPXSvInputStreamImpl::subStreamCount() { - if (!name) - return 0; - OUString rPath(name,strlen(name),RTL_TEXTENCODING_UTF8); - std::vector aElems; - splitPath( aElems, rPath ); - if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is()) return 0; - sal_Int64 tmpPosition = mxSeekable->getPosition(); + PositionHolder pos(mxSeekable); mxSeekable->seek(0); - SvStream *pStream = utl::UcbStreamHelper::CreateStream( mxStream ); - - if (!pStream || !SotStorage::IsOLEStorage( pStream )) + if (isOLE()) { - mxSeekable->seek(tmpPosition); - return 0; + ensureOLEIsInitialized(); + + return mpOLEStorage->maStreams.size(); } - SotStorageRefWrapper storageRefWrapper; - storageRefWrapper.ref = new SotStorage( pStream, sal_True ); - mxChildrenStorages.push_back( storageRefWrapper ); + return 0; +} + +const char *WPXSvInputStreamImpl::subStreamName(const unsigned id) +{ + if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is()) + return 0; + + PositionHolder pos(mxSeekable); + mxSeekable->seek(0); - unsigned i = 0; - while (i < aElems.size()) + if (isOLE()) { - if( mxChildrenStorages.back().ref->IsStream(aElems[i])) - break; - else if (mxChildrenStorages.back().ref->IsStorage(aElems[i])) - { - SotStorageRef tmpParent(mxChildrenStorages.back().ref); - storageRefWrapper.ref = tmpParent->OpenSotStorage(aElems[i++], STREAM_STD_READ); - mxChildrenStorages.push_back(storageRefWrapper); - } - else - // should not happen + ensureOLEIsInitialized(); + + if (mpOLEStorage->maStreams.size() <= id) return 0; + + return mpOLEStorage->maStreams[id].name.getStr(); } - // For the while don't return stream in this situation. - // Later, given how libcdr's zip stream implementation behaves, - // return the first stream in the storage if there is one. - if (i >= aElems.size()) + return 0; +} + +bool WPXSvInputStreamImpl::existsSubStream(const char *const name) +{ + if (!name) return 0; - SotStorageStreamRefWrapper storageStreamRefWrapper; - storageStreamRefWrapper.ref = mxChildrenStorages.back().ref->OpenSotStream( aElems[i], STREAM_STD_READ ); - mxChildrenStreams.push_back( storageStreamRefWrapper ); + if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is()) + return false; - mxSeekable->seek(tmpPosition); + PositionHolder pos(mxSeekable); + mxSeekable->seek(0); - if ( !mxChildrenStreams.back().ref.Is() || mxChildrenStreams.back().ref->GetError() ) + if (isOLE()) { - mxSeekable->seek(tmpPosition); - return 0; + ensureOLEIsInitialized(); + + const rtl::OUString aName(rtl::OStringToOUString(rtl::OString(name), RTL_TEXTENCODING_UTF8)); + return mpOLEStorage->maNameMap.end() != mpOLEStorage->maNameMap.find(aName); } - Reference < XInputStream > xContents(new utl::OSeekableInputStreamWrapper( mxChildrenStreams.back().ref )); - mxSeekable->seek(tmpPosition); - if (xContents.is()) - return new WPXSvInputStream( xContents ); - else + return false; +} + +WPXInputStream *WPXSvInputStreamImpl::getSubStreamByName(const char *const name) +{ + if (!name) return 0; + + if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is()) + return 0; + + PositionHolder pos(mxSeekable); + mxSeekable->seek(0); + + if (isOLE()) + { + ensureOLEIsInitialized(); + + const rtl::OUString aName(rtl::OStringToOUString(rtl::OString(name), RTL_TEXTENCODING_UTF8)); + return createWPXStream(mpOLEStorage->getStream(aName)); + } + + return 0; } +WPXInputStream *WPXSvInputStreamImpl::getSubStreamById(const unsigned id) +{ + if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is()) + return 0; + + PositionHolder pos(mxSeekable); + mxSeekable->seek(0); + + if (isOLE()) + { + ensureOLEIsInitialized(); + + if (mpOLEStorage->maStreams.size() <= id) + return 0; + + return createWPXStream(mpOLEStorage->getStream(id)); + } + + return 0; +} void WPXSvInputStreamImpl::invalidateReadBuffer() { @@ -259,6 +473,39 @@ void WPXSvInputStreamImpl::invalidateReadBuffer() } } +WPXInputStream *WPXSvInputStreamImpl::createWPXStream(const SotStorageStreamRef &rxStorage) +{ + Reference < XInputStream > xContents(new utl::OSeekableInputStreamWrapper( rxStorage )); + if (xContents.is()) + return new WPXSvInputStream( xContents ); + else + return 0; +} + +bool WPXSvInputStreamImpl::isOLE() +{ + if (!mbCheckedOLE) + { + assert(0 == mxSeekable->getPosition()); + + boost::scoped_ptr pStream(utl::UcbStreamHelper::CreateStream( mxStream )); + if (pStream && SotStorage::IsOLEStorage(pStream.get())) + mpOLEStorage.reset(new OLEStorageImpl()); + + mbCheckedOLE = true; + } + + return bool(mpOLEStorage); +} + +void WPXSvInputStreamImpl::ensureOLEIsInitialized() +{ + assert(mpOLEStorage); + + if (!mpOLEStorage->mbInitialized) + mpOLEStorage->initialize(utl::UcbStreamHelper::CreateStream( mxStream )); +} + WPXSvInputStream::WPXSvInputStream( Reference< XInputStream > xStream ) : mpImpl(new WPXSvInputStreamImpl(xStream)) { @@ -368,21 +615,60 @@ int WPXSvInputStream::seek(long offset, WPX_SEEK_TYPE seekType) return retVal; } +bool WPXSvInputStream::isEnd() +{ + return mpImpl->isEnd() && mpImpl->mnReadBufferPos == mpImpl->mnReadBufferLength; +} + +bool WPXSvInputStream::isStructured() +{ + mpImpl->invalidateReadBuffer(); + return mpImpl->isStructured(); +} + +unsigned WPXSvInputStream::subStreamCount() +{ + mpImpl->invalidateReadBuffer(); + return mpImpl->subStreamCount(); +} + +const char *WPXSvInputStream::subStreamName(const unsigned id) +{ + mpImpl->invalidateReadBuffer(); + return mpImpl->subStreamName(id); +} + +bool WPXSvInputStream::existsSubStream(const char *const name) +{ + mpImpl->invalidateReadBuffer(); + return mpImpl->existsSubStream(name); +} + +WPXInputStream *WPXSvInputStream::getSubStreamByName(const char *name) +{ + mpImpl->invalidateReadBuffer(); + return mpImpl->getSubStreamByName(name); +} + +WPXInputStream *WPXSvInputStream::getSubStreamById(const unsigned id) +{ + mpImpl->invalidateReadBuffer(); + return mpImpl->getSubStreamById(id); +} + bool WPXSvInputStream::atEOS() { - return mpImpl->atEOS() && mpImpl->mnReadBufferPos == mpImpl->mnReadBufferLength; + return isEnd(); } bool WPXSvInputStream::isOLEStream() { - mpImpl->invalidateReadBuffer(); - return mpImpl->isOLEStream(); + return isStructured(); } WPXInputStream *WPXSvInputStream::getDocumentOLEStream(const char *name) { - mpImpl->invalidateReadBuffer(); - return mpImpl->getDocumentOLEStream(name); + return getSubStreamByName(name); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/writerperfect/source/common/WPXSvStream.hxx b/writerperfect/source/common/WPXSvStream.hxx index d104c4b341cc..efb627accae4 100644 --- a/writerperfect/source/common/WPXSvStream.hxx +++ b/writerperfect/source/common/WPXSvStream.hxx @@ -25,12 +25,20 @@ public: ::com::sun::star::io::XInputStream > xStream ); virtual ~WPXSvInputStream(); - virtual bool isOLEStream(); - virtual WPXInputStream * getDocumentOLEStream(const char *name); + virtual bool isStructured(); + virtual unsigned subStreamCount(); + virtual const char * subStreamName(unsigned id); + virtual bool existsSubStream(const char *name); + virtual WPXInputStream * getSubStreamByName(const char *name); + virtual WPXInputStream * getSubStreamById(unsigned id); virtual const unsigned char *read(unsigned long numBytes, unsigned long &numBytesRead); virtual int seek(long offset, WPX_SEEK_TYPE seekType); virtual long tell(); + virtual bool isEnd(); + + virtual bool isOLEStream(); + virtual WPXInputStream * getDocumentOLEStream(const char *name); virtual bool atEOS(); private: -- cgit v1.2.3