From 723863ff26f46e294adde61009b85f6f0e28b5b0 Mon Sep 17 00:00:00 2001 From: David Tardon Date: Wed, 15 Jan 2014 21:15:28 +0100 Subject: finish zip support in WPXSvInputStream Change-Id: I48017873991abdc054e8be93912f2b2f5ae4383f --- writerperfect/source/common/WPXSvStream.cxx | 250 +++++++++++++++++++++++++--- 1 file changed, 231 insertions(+), 19 deletions(-) (limited to 'writerperfect') diff --git a/writerperfect/source/common/WPXSvStream.cxx b/writerperfect/source/common/WPXSvStream.cxx index 9bc69849da9c..0084ec3039d6 100644 --- a/writerperfect/source/common/WPXSvStream.cxx +++ b/writerperfect/source/common/WPXSvStream.cxx @@ -9,7 +9,10 @@ #include "WPXSvStream.hxx" +#include #include +#include +#include #include #include @@ -86,9 +89,9 @@ const rtl::OUString concatPath(const rtl::OUString &lhs, const rtl::OUString &rh return lhs + "/" + rhs; } -struct StreamData +struct OLEStreamData { - explicit StreamData(const rtl::OString &rName); + explicit OLEStreamData(const rtl::OString &rName); SotStorageStreamRefWrapper stream; @@ -136,12 +139,12 @@ private: public: SotStorageRefWrapper mxRootStorage; //< root storage of the OLE2 OLEStorageMap_t maStorageMap; //< map of all sub storages by name - ::std::vector< StreamData > maStreams; //< list of streams and their names + ::std::vector< OLEStreamData > maStreams; //< list of streams and their names NameMap_t maNameMap; //< map of stream names to indexes (into @c maStreams) bool mbInitialized; }; -StreamData::StreamData(const rtl::OString &rName) +OLEStreamData::OLEStreamData(const rtl::OString &rName) : stream() , name(rName) { @@ -202,7 +205,7 @@ void OLEStorageImpl::traverse(const SotStorageRef &rStorage, const rtl::OUString { if (aIt->IsStream()) { - maStreams.push_back(StreamData(rtl::OUStringToOString(aIt->GetName(), RTL_TEXTENCODING_UTF8))); + maStreams.push_back(OLEStreamData(rtl::OUStringToOString(aIt->GetName(), RTL_TEXTENCODING_UTF8))); maNameMap[concatPath(rPath, aIt->GetName())] = maStreams.size() - 1; } else if (aIt->IsStorage()) @@ -243,6 +246,162 @@ SotStorageStreamRef OLEStorageImpl::createStream(const rtl::OUString &rPath) } +namespace +{ + +struct ZipStreamData +{ + explicit ZipStreamData(const rtl::OString &rName); + + Reference xStream; + + /** Name of the stream. + * + * This is not @c rtl::OUString, because we need to be able to + * produce const char* from it. + */ + rtl::OString aName; +}; + +typedef boost::unordered_map, rtl::OUStringHash> ZipStorageMap_t; + +/** Representation of a Zip storage. + * + * This is quite similar to OLEStorageImpl, except that we do not need + * to keep all storages (folders) open. + */ +struct ZipStorageImpl +{ + ZipStorageImpl(const Reference &rxRoot); + + /** Initialize for access. + * + * This creates a bidirectional map of stream names to their + * indexes (index of a stream is determined by deep-first + * traversal). + */ + void initialize(); + + Reference getStream(const rtl::OUString &rPath); + Reference getStream(std::size_t nId); + +private: + void traverse(const Reference &rxEnum, const rtl::OUString &rPath); + + Reference createStream(const rtl::OUString &rPath); + +public: + Reference mxRoot; //< root of the Zip + ::std::vector< ZipStreamData > maStreams; //< list of streams and their names + NameMap_t maNameMap; //< map of stream names to indexes (into @c maStreams) + bool mbInitialized; +}; + +ZipStreamData::ZipStreamData(const rtl::OString &rName) + : xStream() + , aName(rName) +{ +} + +ZipStorageImpl::ZipStorageImpl(const Reference &rxRoot) + : mxRoot(rxRoot) + , maStreams() + , maNameMap() + , mbInitialized(false) +{ + assert(mxRoot.is()); +} + +void ZipStorageImpl::initialize() +{ + const Reference xEnum(mxRoot, UNO_QUERY); + + if (xEnum.is()) + traverse(xEnum->createEnumeration(), ""); + + mbInitialized = true; +} + +Reference ZipStorageImpl::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 Reference(); + + if (!maStreams[aIt->second].xStream.is()) + maStreams[aIt->second].xStream = createStream(rPath); + + return maStreams[aIt->second].xStream; +} + +Reference ZipStorageImpl::getStream(const std::size_t nId) +{ + if (!maStreams[nId].xStream.is()) + maStreams[nId].xStream = createStream(rtl::OStringToOUString(maStreams[nId].aName, RTL_TEXTENCODING_UTF8)); + + return maStreams[nId].xStream; +} + +void ZipStorageImpl::traverse(const Reference &rxEnum, const rtl::OUString &rPath) +{ + while (rxEnum->hasMoreElements()) + { + Any aItem; + try + { + aItem = rxEnum->nextElement(); + } + catch (const Exception &) + { + continue; + } + + const Reference xNamed(aItem, UNO_QUERY); + const Reference xSink(aItem, UNO_QUERY); + const Reference xEnum(aItem, UNO_QUERY); + + if (xSink.is() && xNamed.is()) + { + maStreams.push_back(ZipStreamData(rtl::OUStringToOString(xNamed->getName(), RTL_TEXTENCODING_UTF8))); + maNameMap[concatPath(rPath, xNamed->getName())] = maStreams.size() - 1; + } + else if (xEnum.is() && xNamed.is()) + { + const rtl::OUString aPath = concatPath(rPath, xNamed->getName()); + + // deep-first traversal + traverse(xEnum->createEnumeration(), aPath); + } + else + { + assert(0); + } + } +} + +Reference ZipStorageImpl::createStream(const rtl::OUString &rPath) +{ + Reference xStream; + + try + { + const Reference xSink(mxRoot->getByHierarchicalName(rPath), UNO_QUERY_THROW); + xStream.set(xSink->getInputStream(), UNO_QUERY_THROW); + } + catch (const Exception &) + { + // nothing needed + } + + return xStream; +} + +} + class WPXSvInputStreamImpl { public : @@ -269,6 +428,7 @@ private: void ensureOLEIsInitialized(); bool isZip(); + void ensureZipIsInitialized(); WPXInputStream *createWPXStream(const SotStorageStreamRef &rxStorage); @@ -277,10 +437,7 @@ private: ::com::sun::star::uno::Reference< ::com::sun::star::io::XSeekable > mxSeekable; ::com::sun::star::uno::Sequence< sal_Int8 > maData; boost::scoped_ptr< OLEStorageImpl > mpOLEStorage; - // TODO: this is not sufficient to implement RVNGInputStream, as - // packages::Package does not support any kind of enumeration of - // its content - ::com::sun::star::uno::Reference< container::XHierarchicalNameAccess > mxZipStorage; + boost::scoped_ptr< ZipStorageImpl > mpZipStorage; bool mbCheckedOLE; bool mbCheckedZip; public: @@ -295,7 +452,7 @@ WPXSvInputStreamImpl::WPXSvInputStreamImpl( Reference< XInputStream > xStream ) mxSeekable(xStream, UNO_QUERY), maData(0), mpOLEStorage(0), - mxZipStorage(), + mpZipStorage(0), mbCheckedOLE(false), mbCheckedZip(false), mnLength(0), @@ -391,7 +548,12 @@ bool WPXSvInputStreamImpl::isStructured() PositionHolder pos(mxSeekable); mxSeekable->seek(0); - return isOLE() || isZip(); + if (isOLE()) + return true; + + mxSeekable->seek(0); + + return isZip(); } unsigned WPXSvInputStreamImpl::subStreamCount() @@ -409,7 +571,14 @@ unsigned WPXSvInputStreamImpl::subStreamCount() return mpOLEStorage->maStreams.size(); } - // TODO: zip impl. + mxSeekable->seek(0); + + if (isZip()) + { + ensureZipIsInitialized(); + + return mpZipStorage->maStreams.size(); + } return 0; } @@ -432,7 +601,17 @@ const char *WPXSvInputStreamImpl::subStreamName(const unsigned id) return mpOLEStorage->maStreams[id].name.getStr(); } - // TODO: zip impl. + mxSeekable->seek(0); + + if (isZip()) + { + ensureZipIsInitialized(); + + if (mpZipStorage->maStreams.size() <= id) + return 0; + + return mpZipStorage->maStreams[id].aName.getStr(); + } return 0; } @@ -456,8 +635,13 @@ bool WPXSvInputStreamImpl::existsSubStream(const char *const name) return mpOLEStorage->maNameMap.end() != mpOLEStorage->maNameMap.find(aName); } + mxSeekable->seek(0); + if (isZip()) - return mxZipStorage->hasByHierarchicalName(aName); + { + ensureZipIsInitialized(); + return mpZipStorage->maNameMap.end() != mpZipStorage->maNameMap.find(aName); + } return false; } @@ -481,12 +665,15 @@ WPXInputStream *WPXSvInputStreamImpl::getSubStreamByName(const char *const name) return createWPXStream(mpOLEStorage->getStream(aName)); } + mxSeekable->seek(0); + if (isZip()) { + ensureZipIsInitialized(); + try { - const Reference xStream(mxZipStorage->getByHierarchicalName(aName), UNO_QUERY_THROW); - return new WPXSvInputStream(xStream->getInputStream()); + return new WPXSvInputStream(mpZipStorage->getStream(aName)); } catch (const Exception &) { @@ -515,8 +702,24 @@ WPXInputStream *WPXSvInputStreamImpl::getSubStreamById(const unsigned id) return createWPXStream(mpOLEStorage->getStream(id)); } - // TODO: zip impl. + mxSeekable->seek(0); + + if (isZip()) + { + ensureZipIsInitialized(); + + if (mpZipStorage->maStreams.size() <= id) + return 0; + try + { + return new WPXSvInputStream(mpZipStorage->getStream(id)); + } + catch (const Exception &) + { + // nothing needed + } + } return 0; } @@ -568,9 +771,10 @@ bool WPXSvInputStreamImpl::isZip() aArgs[0] <<= mxStream; const Reference xContext(comphelper::getProcessComponentContext(), UNO_QUERY_THROW); - mxZipStorage.set( + const Reference xZipStorage( xContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.packages.Package", aArgs, xContext), UNO_QUERY_THROW); + mpZipStorage.reset(new ZipStorageImpl(xZipStorage)); } catch (const Exception &) { @@ -580,7 +784,7 @@ bool WPXSvInputStreamImpl::isZip() mbCheckedZip = true; } - return mxZipStorage.is(); + return bool(mpZipStorage); } void WPXSvInputStreamImpl::ensureOLEIsInitialized() @@ -591,6 +795,14 @@ void WPXSvInputStreamImpl::ensureOLEIsInitialized() mpOLEStorage->initialize(utl::UcbStreamHelper::CreateStream( mxStream )); } +void WPXSvInputStreamImpl::ensureZipIsInitialized() +{ + assert(mpZipStorage); + + if (!mpZipStorage->mbInitialized) + mpZipStorage->initialize(); +} + WPXSvInputStream::WPXSvInputStream( Reference< XInputStream > xStream ) : mpImpl(new WPXSvInputStreamImpl(xStream)) { -- cgit