LCOV - code coverage report
Current view: top level - writerperfect/source/common - WPXSvInputStream.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 337 369 91.3 %
Date: 2015-06-13 12:38:46 Functions: 64 65 98.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  */
       9             : 
      10             : #include <WPXSvInputStream.hxx>
      11             : 
      12             : #include <com/sun/star/packages/zip/XZipFileAccess2.hpp>
      13             : #include <com/sun/star/uno/Any.hxx>
      14             : 
      15             : #include <comphelper/processfactory.hxx>
      16             : #include <comphelper/seekableinput.hxx>
      17             : 
      18             : #include <rtl/string.hxx>
      19             : 
      20             : #include <sot/storage.hxx>
      21             : 
      22             : #include <tools/stream.hxx>
      23             : #include <unotools/streamwrap.hxx>
      24             : #include <unotools/ucbstreamhelper.hxx>
      25             : 
      26             : #include <limits>
      27             : #include <vector>
      28             : 
      29             : #include <boost/noncopyable.hpp>
      30             : #include <boost/scoped_ptr.hpp>
      31             : #include <unordered_map>
      32             : 
      33             : namespace writerperfect
      34             : {
      35             : 
      36             : using namespace ::com::sun::star::uno;
      37             : using namespace ::com::sun::star::io;
      38             : 
      39             : namespace container = com::sun::star::container;
      40             : namespace lang = com::sun::star::lang;
      41             : namespace packages = com::sun::star::packages;
      42             : 
      43             : namespace
      44             : {
      45             : 
      46             : class PositionHolder : boost::noncopyable
      47             : {
      48             : public:
      49             :     explicit PositionHolder(const Reference<XSeekable> &rxSeekable);
      50             :     ~PositionHolder();
      51             : 
      52             : private:
      53             :     const Reference<XSeekable> mxSeekable;
      54             :     const sal_uInt64 mnPosition;
      55             : };
      56             : 
      57        7987 : PositionHolder::PositionHolder(const Reference<XSeekable> &rxSeekable)
      58             :     : mxSeekable(rxSeekable)
      59        7987 :     , mnPosition(rxSeekable->getPosition())
      60             : {
      61        7987 : }
      62             : 
      63       15974 : PositionHolder::~PositionHolder() try
      64             : {
      65        7987 :     mxSeekable->seek(mnPosition);
      66             : }
      67           0 : catch (...)
      68             : {
      69        7987 : }
      70             : 
      71             : } // anonymous namespace
      72             : 
      73             : typedef struct
      74         129 : {
      75             :     tools::SvRef<SotStorage> ref;
      76         179 : } SotStorageRefWrapper;
      77             : 
      78             : typedef struct
      79         126 : {
      80             :     tools::SvRef<SotStorageStream> ref;
      81         668 : } SotStorageStreamRefWrapper;
      82             : 
      83             : namespace
      84             : {
      85             : 
      86         162 : rtl::OUString lcl_normalizeSubStreamPath(const rtl::OUString &rPath)
      87             : {
      88             :     // accept paths which begin by '/'
      89             :     // TODO: maybe this should to a full normalization
      90         162 :     if (rPath.startsWith("/") && rPath.getLength() >= 2)
      91           0 :         return rPath.copy(1);
      92         162 :     return rPath;
      93             : }
      94             : 
      95             : }
      96             : 
      97             : namespace
      98             : {
      99             : 
     100         302 : const rtl::OUString concatPath(const rtl::OUString &lhs, const rtl::OUString &rhs)
     101             : {
     102         302 :     if (lhs.isEmpty())
     103         244 :         return rhs;
     104          58 :     return lhs + "/" + rhs;
     105             : }
     106             : 
     107         668 : struct OLEStreamData
     108             : {
     109             :     explicit OLEStreamData(const rtl::OString &rName);
     110             : 
     111             :     SotStorageStreamRefWrapper stream;
     112             : 
     113             :     /** Name of the stream.
     114             :       *
     115             :       * This is not @c rtl::OUString, because we need to be able to
     116             :       * produce const char* from it.
     117             :       */
     118             :     rtl::OString name;
     119             : };
     120             : 
     121             : typedef std::unordered_map<rtl::OUString, std::size_t, rtl::OUStringHash> NameMap_t;
     122             : typedef std::unordered_map<rtl::OUString, SotStorageRefWrapper, rtl::OUStringHash> OLEStorageMap_t;
     123             : 
     124             : /** Representation of an OLE2 storage.
     125             :   *
     126             :   * This class tries to bring a bit of sanity to use of SotStorage with
     127             :   * respect to the needs of @c librevenge::RVNGInputStream API. It
     128             :   * holds all nested storages for the whole lifetime (more precisely,
     129             :   * since initialization, which is performed by calling @c
     130             :   * initialize()), thus ensuring that no created stream is destroyed
     131             :   * just because its parent storage went out of scope. It also holds a
     132             :   * bidirectional map of stream names to their indexes (index of a
     133             :   * stream is determined by deep-first traversal), which is also
     134             :   * populated during initialization (member variables @c maStreams and
     135             :   * @c maNameMap).
     136             :   *
     137             :   * Streams are created on demand (and saved, for the same reason as
     138             :   * storages).
     139             :   */
     140          29 : struct OLEStorageImpl
     141             : {
     142             :     OLEStorageImpl();
     143             : 
     144             :     void initialize(SvStream *pStream);
     145             : 
     146             :     tools::SvRef<SotStorageStream> getStream(const rtl::OUString &rPath);
     147             :     tools::SvRef<SotStorageStream> getStream(std::size_t nId);
     148             : 
     149             : private:
     150             :     void traverse(const tools::SvRef<SotStorage> &rStorage, const rtl::OUString &rPath);
     151             : 
     152             :     tools::SvRef<SotStorageStream> createStream(const rtl::OUString &rPath);
     153             : 
     154             : public:
     155             :     SotStorageRefWrapper mxRootStorage; //< root storage of the OLE2
     156             :     OLEStorageMap_t maStorageMap; //< map of all sub storages by name
     157             :     ::std::vector< OLEStreamData > maStreams; //< list of streams and their names
     158             :     NameMap_t maNameMap; //< map of stream names to indexes (into @c maStreams)
     159             :     bool mbInitialized;
     160             : };
     161             : 
     162         126 : OLEStreamData::OLEStreamData(const rtl::OString &rName)
     163             :     : stream()
     164         126 :     , name(rName)
     165             : {
     166         126 : }
     167             : 
     168          29 : OLEStorageImpl::OLEStorageImpl()
     169             :     : mxRootStorage()
     170             :     , maStorageMap()
     171             :     , maStreams()
     172             :     , maNameMap()
     173          29 :     , mbInitialized(false)
     174             : {
     175          29 : }
     176             : 
     177          29 : void OLEStorageImpl::initialize(SvStream *const pStream)
     178             : {
     179          29 :     if (!pStream)
     180          29 :         return;
     181             : 
     182          29 :     mxRootStorage.ref = new SotStorage(pStream, true);
     183             : 
     184          29 :     traverse(mxRootStorage.ref, "");
     185             : 
     186          29 :     mbInitialized = true;
     187             : }
     188             : 
     189          98 : tools::SvRef<SotStorageStream> OLEStorageImpl::getStream(const rtl::OUString &rPath)
     190             : {
     191          98 :     const rtl::OUString aPath(lcl_normalizeSubStreamPath(rPath));
     192          98 :     NameMap_t::iterator aIt = maNameMap.find(aPath);
     193             : 
     194             :     // For the while don't return stream in this situation.
     195             :     // Later, given how libcdr's zip stream implementation behaves,
     196             :     // return the first stream in the storage if there is one.
     197          98 :     if (maNameMap.end() == aIt)
     198           8 :         return tools::SvRef<SotStorageStream>();
     199             : 
     200          90 :     if (!maStreams[aIt->second].stream.ref.Is())
     201          63 :         maStreams[aIt->second].stream.ref = createStream(aPath);
     202             : 
     203          90 :     return maStreams[aIt->second].stream.ref;
     204             : }
     205             : 
     206           2 : tools::SvRef<SotStorageStream> OLEStorageImpl::getStream(const std::size_t nId)
     207             : {
     208           2 :     if (!maStreams[nId].stream.ref.Is())
     209           2 :         maStreams[nId].stream.ref = createStream(rtl::OStringToOUString(maStreams[nId].name, RTL_TEXTENCODING_UTF8));
     210             : 
     211           2 :     return maStreams[nId].stream.ref;
     212             : }
     213             : 
     214          79 : void OLEStorageImpl::traverse(const tools::SvRef<SotStorage> &rStorage, const rtl::OUString &rPath)
     215             : {
     216          79 :     SvStorageInfoList infos;
     217             : 
     218          79 :     rStorage->FillInfoList(&infos);
     219             : 
     220         255 :     for (SvStorageInfoList::const_iterator aIt = infos.begin(); infos.end() != aIt; ++aIt)
     221             :     {
     222         176 :         if (aIt->IsStream())
     223             :         {
     224         126 :             maStreams.push_back(OLEStreamData(rtl::OUStringToOString(concatPath(rPath, aIt->GetName()), RTL_TEXTENCODING_UTF8)));
     225         126 :             maNameMap[concatPath(rPath, aIt->GetName())] = maStreams.size() - 1;
     226             :         }
     227          50 :         else if (aIt->IsStorage())
     228             :         {
     229          50 :             const rtl::OUString aPath = concatPath(rPath, aIt->GetName());
     230         100 :             SotStorageRefWrapper xStorage;
     231          50 :             xStorage.ref = rStorage->OpenSotStorage(aIt->GetName(), STREAM_STD_READ);
     232          50 :             maStorageMap[aPath] = xStorage;
     233             : 
     234             :             // deep-first traversal
     235         100 :             traverse(xStorage.ref, aPath);
     236             :         }
     237             :         else
     238             :         {
     239             :             SAL_WARN("writerperfect", "OLEStorageImpl::traverse: invalid storage entry, neither stream nor file");
     240             :         }
     241          79 :     }
     242          79 : }
     243             : 
     244          65 : tools::SvRef<SotStorageStream> OLEStorageImpl::createStream(const rtl::OUString &rPath)
     245             : {
     246          65 :     const sal_Int32 nDelim = rPath.lastIndexOf(sal_Unicode('/'));
     247             : 
     248          65 :     if (-1 == nDelim)
     249          49 :         return mxRootStorage.ref->OpenSotStream(rPath, STREAM_STD_READ);
     250             : 
     251          16 :     const rtl::OUString aDir = rPath.copy(0, nDelim);
     252          32 :     const rtl::OUString aName = rPath.copy(nDelim + 1);
     253             : 
     254          16 :     const OLEStorageMap_t::const_iterator aIt = maStorageMap.find(aDir);
     255             : 
     256          16 :     if (maStorageMap.end() == aIt)
     257           0 :         return 0;
     258             : 
     259          32 :     return aIt->second.ref->OpenSotStream(aName, STREAM_STD_READ);
     260             : }
     261             : 
     262             : }
     263             : 
     264             : namespace
     265             : {
     266             : 
     267        5505 : struct ZipStreamData
     268             : {
     269             :     explicit ZipStreamData(const rtl::OString &rName);
     270             : 
     271             :     Reference<XInputStream> xStream;
     272             : 
     273             :     /** Name of the stream.
     274             :       *
     275             :       * This is not @c rtl::OUString, because we need to be able to
     276             :       * produce const char* from it.
     277             :       */
     278             :     rtl::OString aName;
     279             : };
     280             : 
     281             : /** Representation of a Zip storage.
     282             :   *
     283             :   * This is quite similar to OLEStorageImpl, except that we do not need
     284             :   * to keep all storages (folders) open.
     285             :   */
     286         190 : struct ZipStorageImpl
     287             : {
     288             :     explicit ZipStorageImpl(const Reference<container::XNameAccess> &rxContainer);
     289             : 
     290             :     /** Initialize for access.
     291             :       *
     292             :       * This creates a bidirectional map of stream names to their
     293             :       * indexes (index of a stream is determined by deep-first
     294             :       * traversal).
     295             :       */
     296             :     void initialize();
     297             : 
     298             :     Reference<XInputStream> getStream(const rtl::OUString &rPath);
     299             :     Reference<XInputStream> getStream(std::size_t nId);
     300             : 
     301             : private:
     302             :     void traverse(const Reference<container::XNameAccess> &rxEnum);
     303             : 
     304             :     Reference<XInputStream> createStream(const rtl::OUString &rPath);
     305             : 
     306             : public:
     307             :     Reference<container::XNameAccess> mxContainer; //< root of the Zip
     308             :     ::std::vector< ZipStreamData > maStreams; //< list of streams and their names
     309             :     NameMap_t maNameMap; //< map of stream names to indexes (into @c maStreams)
     310             :     bool mbInitialized;
     311             : };
     312             : 
     313        1835 : ZipStreamData::ZipStreamData(const rtl::OString &rName)
     314             :     : xStream()
     315        1835 :     , aName(rName)
     316             : {
     317        1835 : }
     318             : 
     319         190 : ZipStorageImpl::ZipStorageImpl(const Reference<container::XNameAccess> &rxContainer)
     320             :     : mxContainer(rxContainer)
     321             :     , maStreams()
     322             :     , maNameMap()
     323         190 :     , mbInitialized(false)
     324             : {
     325             :     assert(mxContainer.is());
     326         190 : }
     327             : 
     328         190 : void ZipStorageImpl::initialize()
     329             : {
     330         190 :     traverse(mxContainer);
     331             : 
     332         190 :     mbInitialized = true;
     333         190 : }
     334             : 
     335          64 : Reference<XInputStream> ZipStorageImpl::getStream(const rtl::OUString &rPath)
     336             : {
     337          64 :     const rtl::OUString aPath(lcl_normalizeSubStreamPath(rPath));
     338          64 :     NameMap_t::iterator aIt = maNameMap.find(aPath);
     339             : 
     340             :     // For the while don't return stream in this situation.
     341             :     // Later, given how libcdr's zip stream implementation behaves,
     342             :     // return the first stream in the storage if there is one.
     343          64 :     if (maNameMap.end() == aIt)
     344          25 :         return Reference<XInputStream>();
     345             : 
     346          39 :     if (!maStreams[aIt->second].xStream.is())
     347          38 :         maStreams[aIt->second].xStream = createStream(aPath);
     348             : 
     349          39 :     return maStreams[aIt->second].xStream;
     350             : }
     351             : 
     352          11 : Reference<XInputStream> ZipStorageImpl::getStream(const std::size_t nId)
     353             : {
     354          11 :     if (!maStreams[nId].xStream.is())
     355          11 :         maStreams[nId].xStream = createStream(rtl::OStringToOUString(maStreams[nId].aName, RTL_TEXTENCODING_UTF8));
     356             : 
     357          11 :     return maStreams[nId].xStream;
     358             : }
     359             : 
     360         190 : void ZipStorageImpl::traverse(const Reference<container::XNameAccess> &rxContainer)
     361             : {
     362         190 :     const Sequence<rtl::OUString> lNames = rxContainer->getElementNames();
     363             : 
     364         190 :     maStreams.reserve(lNames.getLength());
     365             : 
     366        2949 :     for (sal_Int32 n = 0; n < lNames.getLength(); ++n)
     367             :     {
     368        2759 :         if (!lNames[n].endsWith("/")) // skip dirs
     369             :         {
     370        1835 :             maStreams.push_back(ZipStreamData(rtl::OUStringToOString(lNames[n], RTL_TEXTENCODING_UTF8)));
     371        1835 :             maNameMap[lNames[n]] = maStreams.size() - 1;
     372             :         }
     373         190 :     }
     374         190 : }
     375             : 
     376          49 : Reference<XInputStream> ZipStorageImpl::createStream(const rtl::OUString &rPath)
     377             : {
     378          49 :     Reference<XInputStream> xStream;
     379             : 
     380             :     try
     381             :     {
     382          49 :         const Reference<XInputStream> xInputStream(mxContainer->getByName(rPath), UNO_QUERY_THROW);
     383          98 :         const Reference<XSeekable> xSeekable(xInputStream, UNO_QUERY);
     384             : 
     385          49 :         if (xSeekable.is())
     386           0 :             xStream = xInputStream;
     387             :         else
     388          98 :             xStream.set(new comphelper::OSeekableInputWrapper(xInputStream, comphelper::getProcessComponentContext()));
     389             :     }
     390           0 :     catch (const Exception &)
     391             :     {
     392             :         // nothing needed
     393             :     }
     394             : 
     395          49 :     return xStream;
     396             : }
     397             : 
     398             : }
     399             : 
     400             : class WPXSvInputStreamImpl
     401             : {
     402             : public :
     403             :     explicit WPXSvInputStreamImpl(::com::sun::star::uno::Reference<
     404             :                          ::com::sun::star::io::XInputStream > xStream);
     405             :     ~WPXSvInputStreamImpl();
     406             : 
     407             :     bool isStructured();
     408             :     unsigned subStreamCount();
     409             :     const char *subStreamName(unsigned id);
     410             :     bool existsSubStream(const char *name);
     411             :     librevenge::RVNGInputStream *getSubStreamByName(const char *name);
     412             :     librevenge::RVNGInputStream *getSubStreamById(unsigned id);
     413             : 
     414             :     const unsigned char *read(unsigned long numBytes, unsigned long &numBytesRead);
     415             :     int seek(long offset);
     416             :     long tell();
     417             :     bool isEnd();
     418             : 
     419             :     void invalidateReadBuffer();
     420             : 
     421             : private:
     422             :     bool isOLE();
     423             :     void ensureOLEIsInitialized();
     424             : 
     425             :     bool isZip();
     426             :     void ensureZipIsInitialized();
     427             : 
     428             :     static librevenge::RVNGInputStream *createWPXStream(const tools::SvRef<SotStorageStream> &rxStorage);
     429             :     static librevenge::RVNGInputStream *createWPXStream(const Reference<XInputStream> &rxStream);
     430             : 
     431             : private:
     432             :     ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > mxStream;
     433             :     ::com::sun::star::uno::Reference< ::com::sun::star::io::XSeekable > mxSeekable;
     434             :     ::com::sun::star::uno::Sequence< sal_Int8 > maData;
     435             :     boost::scoped_ptr< OLEStorageImpl > mpOLEStorage;
     436             :     boost::scoped_ptr< ZipStorageImpl > mpZipStorage;
     437             :     bool mbCheckedOLE;
     438             :     bool mbCheckedZip;
     439             : public:
     440             :     sal_Int64 mnLength;
     441             :     const unsigned char *mpReadBuffer;
     442             :     unsigned long mnReadBufferLength;
     443             :     unsigned long mnReadBufferPos;
     444             : };
     445             : 
     446        6029 : WPXSvInputStreamImpl::WPXSvInputStreamImpl(Reference< XInputStream > xStream) :
     447             :     mxStream(xStream),
     448             :     mxSeekable(xStream, UNO_QUERY),
     449             :     maData(0),
     450             :     mpOLEStorage(0),
     451             :     mpZipStorage(0),
     452             :     mbCheckedOLE(false),
     453             :     mbCheckedZip(false),
     454             :     mnLength(0),
     455             :     mpReadBuffer(0),
     456             :     mnReadBufferLength(0),
     457        6029 :     mnReadBufferPos(0)
     458             : {
     459        6029 :     if (!xStream.is() || !mxStream.is())
     460           0 :         mnLength = 0;
     461             :     else
     462             :     {
     463        6029 :         if (!mxSeekable.is())
     464           0 :             mnLength = 0;
     465             :         else
     466             :         {
     467             :             try
     468             :             {
     469        6029 :                 mnLength = mxSeekable->getLength();
     470        6029 :                 if (0 < mxSeekable->getPosition())
     471         129 :                     mxSeekable->seek(0);
     472             :             }
     473           0 :             catch (...)
     474             :             {
     475             :                 SAL_WARN("writerperfect", "mnLength = mxSeekable->getLength() threw exception");
     476           0 :                 mnLength = 0;
     477             :             }
     478             :         }
     479             :     }
     480        6029 : }
     481             : 
     482        6028 : WPXSvInputStreamImpl::~WPXSvInputStreamImpl()
     483             : {
     484        6028 : }
     485             : 
     486       12009 : const unsigned char *WPXSvInputStreamImpl::read(unsigned long numBytes, unsigned long &numBytesRead)
     487             : {
     488       12009 :     numBytesRead = 0;
     489             : 
     490       12009 :     if (numBytes == 0 || isEnd())
     491           9 :         return 0;
     492             : 
     493       12000 :     numBytesRead = mxStream->readSomeBytes(maData, numBytes);
     494       12000 :     if (numBytesRead == 0)
     495           0 :         return 0;
     496             : 
     497       12000 :     return reinterpret_cast<const unsigned char *>(maData.getConstArray());
     498             : }
     499             : 
     500     1658288 : long WPXSvInputStreamImpl::tell()
     501             : {
     502     1658288 :     if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
     503           0 :         return -1L;
     504             :     else
     505             :     {
     506     1658288 :         sal_Int64 tmpPosition = mxSeekable->getPosition();
     507     1658288 :         if ((tmpPosition < 0) || (tmpPosition > LONG_MAX))
     508           0 :             return -1L;
     509     1658288 :         return (long)tmpPosition;
     510             :     }
     511             : }
     512             : 
     513       44970 : int WPXSvInputStreamImpl::seek(long offset)
     514             : {
     515       44970 :     if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
     516           0 :         return -1;
     517             : 
     518       44970 :     sal_Int64 tmpPosition = mxSeekable->getPosition();
     519       44970 :     if ((tmpPosition < 0) || (tmpPosition > LONG_MAX))
     520           0 :         return -1;
     521             : 
     522             :     try
     523             :     {
     524       44970 :         mxSeekable->seek(offset);
     525       44970 :         return 0;
     526             :     }
     527           0 :     catch (...)
     528             :     {
     529             :         SAL_WARN("writerperfect", "mxSeekable->seek(offset) threw exception");
     530           0 :         return -1;
     531             :     }
     532             : }
     533             : 
     534    29886998 : bool WPXSvInputStreamImpl::isEnd()
     535             : {
     536    29886998 :     if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
     537           0 :         return true;
     538    29886998 :     return (mxSeekable->getPosition() >= mnLength);
     539             : }
     540             : 
     541        5798 : bool WPXSvInputStreamImpl::isStructured()
     542             : {
     543        5798 :     if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
     544           0 :         return false;
     545             : 
     546        5798 :     PositionHolder pos(mxSeekable);
     547        5798 :     mxSeekable->seek(0);
     548             : 
     549        5798 :     if (isOLE())
     550         103 :         return true;
     551             : 
     552        5695 :     mxSeekable->seek(0);
     553             : 
     554        5695 :     return isZip();
     555             : }
     556             : 
     557         383 : unsigned WPXSvInputStreamImpl::subStreamCount()
     558             : {
     559         383 :     if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
     560           0 :         return 0;
     561             : 
     562         383 :     PositionHolder pos(mxSeekable);
     563         383 :     mxSeekable->seek(0);
     564             : 
     565         383 :     if (isOLE())
     566             :     {
     567          18 :         ensureOLEIsInitialized();
     568             : 
     569          18 :         return mpOLEStorage->maStreams.size();
     570             :     }
     571             : 
     572         365 :     mxSeekable->seek(0);
     573             : 
     574         365 :     if (isZip())
     575             :     {
     576         364 :         ensureZipIsInitialized();
     577             : 
     578         364 :         return mpZipStorage->maStreams.size();
     579             :     }
     580             : 
     581           1 :     return 0;
     582             : }
     583             : 
     584        1456 : const char *WPXSvInputStreamImpl::subStreamName(const unsigned id)
     585             : {
     586        1456 :     if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
     587           0 :         return 0;
     588             : 
     589        1456 :     PositionHolder pos(mxSeekable);
     590        1456 :     mxSeekable->seek(0);
     591             : 
     592        1456 :     if (isOLE())
     593             :     {
     594          32 :         ensureOLEIsInitialized();
     595             : 
     596          32 :         if (mpOLEStorage->maStreams.size() <= id)
     597           0 :             return 0;
     598             : 
     599          32 :         return mpOLEStorage->maStreams[id].name.getStr();
     600             :     }
     601             : 
     602        1424 :     mxSeekable->seek(0);
     603             : 
     604        1424 :     if (isZip())
     605             :     {
     606        1423 :         ensureZipIsInitialized();
     607             : 
     608        1423 :         if (mpZipStorage->maStreams.size() <= id)
     609           0 :             return 0;
     610             : 
     611        1423 :         return mpZipStorage->maStreams[id].aName.getStr();
     612             :     }
     613             : 
     614           1 :     return 0;
     615             : }
     616             : 
     617         171 : bool WPXSvInputStreamImpl::existsSubStream(const char *const name)
     618             : {
     619         171 :     if (!name)
     620           0 :         return false;
     621             : 
     622         171 :     if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
     623           0 :         return false;
     624             : 
     625         171 :     PositionHolder pos(mxSeekable);
     626         171 :     mxSeekable->seek(0);
     627             : 
     628         342 :     const rtl::OUString aName(rtl::OStringToOUString(rtl::OString(name), RTL_TEXTENCODING_UTF8));
     629             : 
     630         171 :     if (isOLE())
     631             :     {
     632           2 :         ensureOLEIsInitialized();
     633           2 :         return mpOLEStorage->maNameMap.end() != mpOLEStorage->maNameMap.find(aName);
     634             :     }
     635             : 
     636         169 :     mxSeekable->seek(0);
     637             : 
     638         169 :     if (isZip())
     639             :     {
     640         168 :         ensureZipIsInitialized();
     641         168 :         return mpZipStorage->maNameMap.end() != mpZipStorage->maNameMap.find(aName);
     642             :     }
     643             : 
     644         172 :     return false;
     645             : }
     646             : 
     647         163 : librevenge::RVNGInputStream *WPXSvInputStreamImpl::getSubStreamByName(const char *const name)
     648             : {
     649         163 :     if (!name)
     650           0 :         return 0;
     651             : 
     652         163 :     if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
     653           0 :         return 0;
     654             : 
     655         163 :     PositionHolder pos(mxSeekable);
     656         163 :     mxSeekable->seek(0);
     657             : 
     658         326 :     const rtl::OUString aName(rtl::OStringToOUString(rtl::OString(name), RTL_TEXTENCODING_UTF8));
     659             : 
     660         163 :     if (isOLE())
     661             :     {
     662          98 :         ensureOLEIsInitialized();
     663          98 :         return createWPXStream(mpOLEStorage->getStream(aName));
     664             :     }
     665             : 
     666          65 :     mxSeekable->seek(0);
     667             : 
     668          65 :     if (isZip())
     669             :     {
     670          64 :         ensureZipIsInitialized();
     671             : 
     672             :         try
     673             :         {
     674          64 :             return createWPXStream(mpZipStorage->getStream(aName));
     675             :         }
     676           0 :         catch (const Exception &)
     677             :         {
     678             :             // nothing needed
     679             :         }
     680             :     }
     681             : 
     682         164 :     return 0;
     683             : }
     684             : 
     685          16 : librevenge::RVNGInputStream *WPXSvInputStreamImpl::getSubStreamById(const unsigned id)
     686             : {
     687          16 :     if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
     688           0 :         return 0;
     689             : 
     690          16 :     PositionHolder pos(mxSeekable);
     691          16 :     mxSeekable->seek(0);
     692             : 
     693          16 :     if (isOLE())
     694             :     {
     695           3 :         ensureOLEIsInitialized();
     696             : 
     697           3 :         if (mpOLEStorage->maStreams.size() <= id)
     698           1 :             return 0;
     699             : 
     700           2 :         return createWPXStream(mpOLEStorage->getStream(id));
     701             :     }
     702             : 
     703          13 :     mxSeekable->seek(0);
     704             : 
     705          13 :     if (isZip())
     706             :     {
     707          12 :         ensureZipIsInitialized();
     708             : 
     709          12 :         if (mpZipStorage->maStreams.size() <= id)
     710           1 :             return 0;
     711             : 
     712             :         try
     713             :         {
     714          11 :             return createWPXStream(mpZipStorage->getStream(id));
     715             :         }
     716           0 :         catch (const Exception &)
     717             :         {
     718             :             // nothing needed
     719             :         }
     720             :     }
     721           1 :     return 0;
     722             : }
     723             : 
     724       47458 : void WPXSvInputStreamImpl::invalidateReadBuffer()
     725             : {
     726       47458 :     if (mpReadBuffer)
     727             :     {
     728        6433 :         seek((long) tell() + (long)mnReadBufferPos - (long)mnReadBufferLength);
     729        6433 :         mpReadBuffer = 0;
     730        6433 :         mnReadBufferPos = 0;
     731        6433 :         mnReadBufferLength = 0;
     732             :     }
     733       47458 : }
     734             : 
     735         100 : librevenge::RVNGInputStream *WPXSvInputStreamImpl::createWPXStream(const tools::SvRef<SotStorageStream> &rxStorage)
     736             : {
     737         100 :     if (rxStorage.Is())
     738             :     {
     739          92 :         Reference < XInputStream > xContents(new utl::OSeekableInputStreamWrapper(rxStorage));
     740          92 :         return new WPXSvInputStream(xContents);
     741             :     }
     742           8 :     return 0;
     743             : }
     744             : 
     745          75 : librevenge::RVNGInputStream *WPXSvInputStreamImpl::createWPXStream(const Reference<XInputStream> &rxStream)
     746             : {
     747          75 :     if (rxStream.is())
     748          50 :         return new WPXSvInputStream(rxStream);
     749             :     else
     750          25 :         return 0;
     751             : }
     752             : 
     753        7987 : bool WPXSvInputStreamImpl::isOLE()
     754             : {
     755        7987 :     if (!mbCheckedOLE)
     756             :     {
     757             :         assert(0 == mxSeekable->getPosition());
     758             : 
     759        5614 :         boost::scoped_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(mxStream));
     760        5614 :         if (pStream && SotStorage::IsOLEStorage(pStream.get()))
     761          29 :             mpOLEStorage.reset(new OLEStorageImpl());
     762             : 
     763        5614 :         mbCheckedOLE = true;
     764             :     }
     765             : 
     766        7987 :     return bool(mpOLEStorage);
     767             : }
     768             : 
     769        7731 : bool WPXSvInputStreamImpl::isZip()
     770             : {
     771        7731 :     if (!mbCheckedZip)
     772             :     {
     773             :         assert(0 == mxSeekable->getPosition());
     774             : 
     775             :         try
     776             :         {
     777        5585 :             Sequence<Any> aArgs(1);
     778        5585 :             aArgs[0] <<= mxStream;
     779             : 
     780       11170 :             const Reference<XComponentContext> xContext(comphelper::getProcessComponentContext(), UNO_QUERY_THROW);
     781             :             const Reference<packages::zip::XZipFileAccess2> xZip(
     782       11170 :                 xContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.packages.zip.ZipFileAccess", aArgs, xContext),
     783        5775 :                 UNO_QUERY_THROW);
     784        5775 :             mpZipStorage.reset(new ZipStorageImpl(xZip));
     785             :         }
     786        5395 :         catch (const Exception &)
     787             :         {
     788             :             // ignore
     789             :         }
     790             : 
     791        5585 :         mbCheckedZip = true;
     792             :     }
     793             : 
     794        7731 :     return bool(mpZipStorage);
     795             : }
     796             : 
     797         153 : void WPXSvInputStreamImpl::ensureOLEIsInitialized()
     798             : {
     799             :     assert(mpOLEStorage);
     800             : 
     801         153 :     if (!mpOLEStorage->mbInitialized)
     802          29 :         mpOLEStorage->initialize(utl::UcbStreamHelper::CreateStream(mxStream));
     803         153 : }
     804             : 
     805        2031 : void WPXSvInputStreamImpl::ensureZipIsInitialized()
     806             : {
     807             :     assert(mpZipStorage);
     808             : 
     809        2031 :     if (!mpZipStorage->mbInitialized)
     810         190 :         mpZipStorage->initialize();
     811        2031 : }
     812             : 
     813        6029 : WPXSvInputStream::WPXSvInputStream(Reference< XInputStream > xStream) :
     814        6029 :     mpImpl(new WPXSvInputStreamImpl(xStream))
     815             : {
     816        6029 : }
     817             : 
     818       12298 : WPXSvInputStream::~WPXSvInputStream()
     819             : {
     820        6028 :     if (mpImpl)
     821        6028 :         delete mpImpl;
     822        6270 : }
     823             : 
     824             : #define BUFFER_MAX 65536
     825             : 
     826    28852068 : const unsigned char *WPXSvInputStream::read(unsigned long numBytes, unsigned long &numBytesRead)
     827             : {
     828    28852068 :     numBytesRead = 0;
     829             : 
     830    28852068 :     if (numBytes == 0 || numBytes > (std::numeric_limits<unsigned long>::max)()/2)
     831          35 :         return 0;
     832             : 
     833    28852033 :     if (mpImpl->mpReadBuffer)
     834             :     {
     835    28840958 :         if ((mpImpl->mnReadBufferPos + numBytes > mpImpl->mnReadBufferPos) && (mpImpl->mnReadBufferPos + numBytes <= mpImpl->mnReadBufferLength))
     836             :         {
     837    28840024 :             const unsigned char *pTmp = mpImpl->mpReadBuffer + mpImpl->mnReadBufferPos;
     838    28840024 :             mpImpl->mnReadBufferPos += numBytes;
     839    28840024 :             numBytesRead = numBytes;
     840    28840024 :             return pTmp;
     841             :         }
     842             : 
     843         934 :         mpImpl->invalidateReadBuffer();
     844             :     }
     845             : 
     846       12009 :     unsigned long curpos = (unsigned long) mpImpl->tell();
     847       12009 :     if (curpos == (unsigned long)-1)  // returned ERROR
     848           0 :         return 0;
     849             : 
     850       24018 :     if ((curpos + numBytes < curpos) /*overflow*/ ||
     851       12009 :             (curpos + numBytes >= (sal_uInt64)mpImpl->mnLength))  /*reading more than available*/
     852             :     {
     853         608 :         numBytes = mpImpl->mnLength - curpos;
     854             :     }
     855             : 
     856       12009 :     if (numBytes < BUFFER_MAX)
     857             :     {
     858       11987 :         if (BUFFER_MAX < mpImpl->mnLength - curpos)
     859         955 :             mpImpl->mnReadBufferLength = BUFFER_MAX;
     860             :         else /* BUFFER_MAX >= mpImpl->mnLength - curpos */
     861       11032 :             mpImpl->mnReadBufferLength = mpImpl->mnLength - curpos;
     862             :     }
     863             :     else
     864          22 :         mpImpl->mnReadBufferLength = numBytes;
     865             : 
     866       12009 :     unsigned long tmpNumBytes(0);
     867       12009 :     mpImpl->mpReadBuffer = mpImpl->read(mpImpl->mnReadBufferLength, tmpNumBytes);
     868       12009 :     if (tmpNumBytes != mpImpl->mnReadBufferLength)
     869           0 :         mpImpl->mnReadBufferLength = tmpNumBytes;
     870             : 
     871       12009 :     mpImpl->mnReadBufferPos = 0;
     872       12009 :     if (!mpImpl->mnReadBufferLength)
     873           9 :         return 0;
     874             : 
     875       12000 :     numBytesRead = numBytes;
     876             : 
     877       12000 :     mpImpl->mnReadBufferPos += numBytesRead;
     878       12000 :     return mpImpl->mpReadBuffer;
     879             : }
     880             : 
     881     1352628 : long WPXSvInputStream::tell()
     882             : {
     883     1352628 :     long retVal = mpImpl->tell();
     884     1352628 :     return retVal - (long)mpImpl->mnReadBufferLength + (long)mpImpl->mnReadBufferPos;
     885             : }
     886             : 
     887      117163 : int WPXSvInputStream::seek(long offset, librevenge::RVNG_SEEK_TYPE seekType)
     888             : {
     889      117163 :     sal_Int64 tmpOffset = offset;
     890      117163 :     if (seekType == librevenge::RVNG_SEEK_CUR)
     891         798 :         tmpOffset += tell();
     892      117163 :     if (seekType == librevenge::RVNG_SEEK_END)
     893        7593 :         tmpOffset += mpImpl->mnLength;
     894             : 
     895      117163 :     int retVal = 0;
     896      117163 :     if (tmpOffset < 0)
     897             :     {
     898           3 :         tmpOffset = 0;
     899           3 :         retVal = -1;
     900             :     }
     901      117163 :     if (tmpOffset > mpImpl->mnLength)
     902             :     {
     903          16 :         tmpOffset = mpImpl->mnLength;
     904          16 :         retVal = -1;
     905             :     }
     906             : 
     907      117163 :     if (tmpOffset < mpImpl->tell() && (unsigned long)tmpOffset >= (unsigned long)mpImpl->tell() - mpImpl->mnReadBufferLength)
     908             :     {
     909       78626 :         mpImpl->mnReadBufferPos = (unsigned long)(tmpOffset + (long) mpImpl->mnReadBufferLength - (long) mpImpl->tell());
     910       78626 :         return retVal;
     911             :     }
     912             : 
     913       38537 :     mpImpl->invalidateReadBuffer();
     914             : 
     915       38537 :     if (mpImpl->seek(tmpOffset))
     916           0 :         return -1;
     917       38537 :     return retVal;
     918             : }
     919             : 
     920    29874998 : bool WPXSvInputStream::isEnd()
     921             : {
     922    29874998 :     return mpImpl->isEnd() && mpImpl->mnReadBufferPos == mpImpl->mnReadBufferLength;
     923             : }
     924             : 
     925        5798 : bool WPXSvInputStream::isStructured()
     926             : {
     927        5798 :     mpImpl->invalidateReadBuffer();
     928        5798 :     return mpImpl->isStructured();
     929             : }
     930             : 
     931         383 : unsigned WPXSvInputStream::subStreamCount()
     932             : {
     933         383 :     mpImpl->invalidateReadBuffer();
     934         383 :     return mpImpl->subStreamCount();
     935             : }
     936             : 
     937        1456 : const char *WPXSvInputStream::subStreamName(const unsigned id)
     938             : {
     939        1456 :     mpImpl->invalidateReadBuffer();
     940        1456 :     return mpImpl->subStreamName(id);
     941             : }
     942             : 
     943         171 : bool WPXSvInputStream::existsSubStream(const char *const name)
     944             : {
     945         171 :     mpImpl->invalidateReadBuffer();
     946         171 :     return mpImpl->existsSubStream(name);
     947             : }
     948             : 
     949         163 : librevenge::RVNGInputStream *WPXSvInputStream::getSubStreamByName(const char *name)
     950             : {
     951         163 :     mpImpl->invalidateReadBuffer();
     952         163 :     return mpImpl->getSubStreamByName(name);
     953             : }
     954             : 
     955          16 : librevenge::RVNGInputStream *WPXSvInputStream::getSubStreamById(const unsigned id)
     956             : {
     957          16 :     mpImpl->invalidateReadBuffer();
     958          16 :     return mpImpl->getSubStreamById(id);
     959             : }
     960             : 
     961             : }
     962             : 
     963             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11