LCOV - code coverage report
Current view: top level - writerperfect/source/common - WPXSvInputStream.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 338 370 91.4 %
Date: 2014-11-03 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 <writerperfect/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 <boost/unordered_map.hpp>
      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        1066 : PositionHolder::PositionHolder(const Reference<XSeekable> &rxSeekable)
      58             :     : mxSeekable(rxSeekable)
      59        1066 :     , mnPosition(rxSeekable->getPosition())
      60             : {
      61        1066 : }
      62             : 
      63        2132 : PositionHolder::~PositionHolder() try
      64             : {
      65        1066 :     mxSeekable->seek(mnPosition);
      66        1066 : }
      67           0 : catch (...)
      68             : {
      69        1066 : }
      70             : 
      71             : } // anonymous namespace
      72             : 
      73             : typedef struct
      74         258 : {
      75             :     SotStorageRef ref;
      76         358 : } SotStorageRefWrapper;
      77             : 
      78             : typedef struct
      79         252 : {
      80             :     SotStorageStreamRef ref;
      81        1336 : } SotStorageStreamRefWrapper;
      82             : 
      83             : namespace
      84             : {
      85             : 
      86         216 : 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         216 :     if (rPath.startsWith("/") && rPath.getLength() >= 2)
      91           0 :         return rPath.copy(1);
      92         216 :     return rPath;
      93             : }
      94             : 
      95             : }
      96             : 
      97             : namespace
      98             : {
      99             : 
     100         604 : const rtl::OUString concatPath(const rtl::OUString &lhs, const rtl::OUString &rhs)
     101             : {
     102         604 :     if (lhs.isEmpty())
     103         488 :         return rhs;
     104         116 :     return lhs + "/" + rhs;
     105             : }
     106             : 
     107        1336 : 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 boost::unordered_map<rtl::OUString, std::size_t, rtl::OUStringHash> NameMap_t;
     122             : typedef boost::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          58 : struct OLEStorageImpl
     141             : {
     142             :     OLEStorageImpl();
     143             : 
     144             :     void initialize(SvStream *pStream);
     145             : 
     146             :     SotStorageStreamRef getStream(const rtl::OUString &rPath);
     147             :     SotStorageStreamRef getStream(std::size_t nId);
     148             : 
     149             : private:
     150             :     void traverse(const SotStorageRef &rStorage, const rtl::OUString &rPath);
     151             : 
     152             :     SotStorageStreamRef 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         252 : OLEStreamData::OLEStreamData(const rtl::OString &rName)
     163             :     : stream()
     164         252 :     , name(rName)
     165             : {
     166         252 : }
     167             : 
     168          58 : OLEStorageImpl::OLEStorageImpl()
     169             :     : mxRootStorage()
     170             :     , maStorageMap()
     171             :     , maStreams()
     172             :     , maNameMap()
     173          58 :     , mbInitialized(false)
     174             : {
     175          58 : }
     176             : 
     177          58 : void OLEStorageImpl::initialize(SvStream *const pStream)
     178             : {
     179          58 :     if (!pStream)
     180          58 :         return;
     181             : 
     182          58 :     mxRootStorage.ref = new SotStorage(pStream, true);
     183             : 
     184          58 :     traverse(mxRootStorage.ref, "");
     185             : 
     186          58 :     mbInitialized = true;
     187             : }
     188             : 
     189         166 : SotStorageStreamRef OLEStorageImpl::getStream(const rtl::OUString &rPath)
     190             : {
     191         166 :     const rtl::OUString aPath(lcl_normalizeSubStreamPath(rPath));
     192         166 :     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         166 :     if (maNameMap.end() == aIt)
     198          12 :         return SotStorageStreamRef();
     199             : 
     200         154 :     if (!maStreams[aIt->second].stream.ref.Is())
     201         116 :         maStreams[aIt->second].stream.ref = createStream(aPath);
     202             : 
     203         154 :     return maStreams[aIt->second].stream.ref;
     204             : }
     205             : 
     206           4 : SotStorageStreamRef OLEStorageImpl::getStream(const std::size_t nId)
     207             : {
     208           4 :     if (!maStreams[nId].stream.ref.Is())
     209           4 :         maStreams[nId].stream.ref = createStream(rtl::OStringToOUString(maStreams[nId].name, RTL_TEXTENCODING_UTF8));
     210             : 
     211           4 :     return maStreams[nId].stream.ref;
     212             : }
     213             : 
     214         158 : void OLEStorageImpl::traverse(const SotStorageRef &rStorage, const rtl::OUString &rPath)
     215             : {
     216         158 :     SvStorageInfoList infos;
     217             : 
     218         158 :     rStorage->FillInfoList(&infos);
     219             : 
     220         510 :     for (SvStorageInfoList::const_iterator aIt = infos.begin(); infos.end() != aIt; ++aIt)
     221             :     {
     222         352 :         if (aIt->IsStream())
     223             :         {
     224         252 :             maStreams.push_back(OLEStreamData(rtl::OUStringToOString(concatPath(rPath, aIt->GetName()), RTL_TEXTENCODING_UTF8)));
     225         252 :             maNameMap[concatPath(rPath, aIt->GetName())] = maStreams.size() - 1;
     226             :         }
     227         100 :         else if (aIt->IsStorage())
     228             :         {
     229         100 :             const rtl::OUString aPath = concatPath(rPath, aIt->GetName());
     230         200 :             SotStorageRefWrapper xStorage;
     231         100 :             xStorage.ref = rStorage->OpenSotStorage(aIt->GetName(), STREAM_STD_READ);
     232         100 :             maStorageMap[aPath] = xStorage;
     233             : 
     234             :             // deep-first traversal
     235         200 :             traverse(xStorage.ref, aPath);
     236             :         }
     237             :         else
     238             :         {
     239             :             assert(false);
     240             :         }
     241         158 :     }
     242         158 : }
     243             : 
     244         120 : SotStorageStreamRef OLEStorageImpl::createStream(const rtl::OUString &rPath)
     245             : {
     246         120 :     const sal_Int32 nDelim = rPath.lastIndexOf(sal_Unicode('/'));
     247             : 
     248         120 :     if (-1 == nDelim)
     249          88 :         return mxRootStorage.ref->OpenSotStream(rPath, STREAM_STD_READ);
     250             : 
     251          32 :     const rtl::OUString aDir = rPath.copy(0, nDelim);
     252          64 :     const rtl::OUString aName = rPath.copy(nDelim + 1);
     253             : 
     254          32 :     const OLEStorageMap_t::const_iterator aIt = maStorageMap.find(aDir);
     255             : 
     256          32 :     if (maStorageMap.end() == aIt)
     257           0 :         return 0;
     258             : 
     259          64 :     return aIt->second.ref->OpenSotStream(aName, STREAM_STD_READ);
     260             : }
     261             : 
     262             : }
     263             : 
     264             : namespace
     265             : {
     266             : 
     267         966 : 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          28 : struct ZipStorageImpl
     287             : {
     288             :     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         322 : ZipStreamData::ZipStreamData(const rtl::OString &rName)
     314             :     : xStream()
     315         322 :     , aName(rName)
     316             : {
     317         322 : }
     318             : 
     319          28 : ZipStorageImpl::ZipStorageImpl(const Reference<container::XNameAccess> &rxContainer)
     320             :     : mxContainer(rxContainer)
     321             :     , maStreams()
     322             :     , maNameMap()
     323          28 :     , mbInitialized(false)
     324             : {
     325             :     assert(mxContainer.is());
     326          28 : }
     327             : 
     328          28 : void ZipStorageImpl::initialize()
     329             : {
     330          28 :     traverse(mxContainer);
     331             : 
     332          28 :     mbInitialized = true;
     333          28 : }
     334             : 
     335          50 : Reference<XInputStream> ZipStorageImpl::getStream(const rtl::OUString &rPath)
     336             : {
     337          50 :     const rtl::OUString aPath(lcl_normalizeSubStreamPath(rPath));
     338          50 :     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          50 :     if (maNameMap.end() == aIt)
     344           6 :         return Reference<XInputStream>();
     345             : 
     346          44 :     if (!maStreams[aIt->second].xStream.is())
     347          32 :         maStreams[aIt->second].xStream = createStream(aPath);
     348             : 
     349          44 :     return maStreams[aIt->second].xStream;
     350             : }
     351             : 
     352          22 : Reference<XInputStream> ZipStorageImpl::getStream(const std::size_t nId)
     353             : {
     354          22 :     if (!maStreams[nId].xStream.is())
     355          22 :         maStreams[nId].xStream = createStream(rtl::OStringToOUString(maStreams[nId].aName, RTL_TEXTENCODING_UTF8));
     356             : 
     357          22 :     return maStreams[nId].xStream;
     358             : }
     359             : 
     360          28 : void ZipStorageImpl::traverse(const Reference<container::XNameAccess> &rxContainer)
     361             : {
     362          28 :     const Sequence<rtl::OUString> lNames = rxContainer->getElementNames();
     363             : 
     364          28 :     maStreams.reserve(lNames.getLength());
     365             : 
     366         406 :     for (sal_Int32 n = 0; n < lNames.getLength(); ++n)
     367             :     {
     368         378 :         if (!lNames[n].endsWithAsciiL("/", 1)) // skip dirs
     369             :         {
     370         322 :             maStreams.push_back(ZipStreamData(rtl::OUStringToOString(lNames[n], RTL_TEXTENCODING_UTF8)));
     371         322 :             maNameMap[lNames[n]] = maStreams.size() - 1;
     372             :         }
     373          28 :     }
     374          28 : }
     375             : 
     376          54 : Reference<XInputStream> ZipStorageImpl::createStream(const rtl::OUString &rPath)
     377             : {
     378          54 :     Reference<XInputStream> xStream;
     379             : 
     380             :     try
     381             :     {
     382          54 :         const Reference<XInputStream> xInputStream(mxContainer->getByName(rPath), UNO_QUERY_THROW);
     383         108 :         const Reference<XSeekable> xSeekable(xInputStream, UNO_QUERY);
     384             : 
     385          54 :         if (xSeekable.is())
     386           0 :             xStream = xInputStream;
     387             :         else
     388         108 :             xStream.set(new comphelper::OSeekableInputWrapper(xInputStream, comphelper::getProcessComponentContext()));
     389             :     }
     390           0 :     catch (const Exception &)
     391             :     {
     392             :         // nothing needed
     393             :     }
     394             : 
     395          54 :     return xStream;
     396             : }
     397             : 
     398             : }
     399             : 
     400             : class WPXSvInputStreamImpl
     401             : {
     402             : public :
     403             :     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             :     librevenge::RVNGInputStream *createWPXStream(const SotStorageStreamRef &rxStorage);
     429             :     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         698 : 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         698 :     mnReadBufferPos(0)
     458             : {
     459         698 :     if (!xStream.is() || !mxStream.is())
     460           0 :         mnLength = 0;
     461             :     else
     462             :     {
     463         698 :         if (!mxSeekable.is())
     464           0 :             mnLength = 0;
     465             :         else
     466             :         {
     467             :             try
     468             :             {
     469         698 :                 mnLength = mxSeekable->getLength();
     470         698 :                 if (0 < mxSeekable->getPosition())
     471         234 :                     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         698 : }
     481             : 
     482         696 : WPXSvInputStreamImpl::~WPXSvInputStreamImpl()
     483             : {
     484         696 : }
     485             : 
     486        1156 : const unsigned char *WPXSvInputStreamImpl::read(unsigned long numBytes, unsigned long &numBytesRead)
     487             : {
     488        1156 :     numBytesRead = 0;
     489             : 
     490        1156 :     if (numBytes == 0 || isEnd())
     491          14 :         return 0;
     492             : 
     493        1142 :     numBytesRead = mxStream->readSomeBytes(maData, numBytes);
     494        1142 :     if (numBytesRead == 0)
     495           0 :         return 0;
     496             : 
     497        1142 :     return (const unsigned char *)maData.getConstArray();
     498             : }
     499             : 
     500     2886676 : long WPXSvInputStreamImpl::tell()
     501             : {
     502     2886676 :     if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
     503           0 :         return -1L;
     504             :     else
     505             :     {
     506     2886676 :         sal_Int64 tmpPosition = mxSeekable->getPosition();
     507     2886676 :         if ((tmpPosition < 0) || (tmpPosition > LONG_MAX))
     508           0 :             return -1L;
     509     2886676 :         return (long)tmpPosition;
     510             :     }
     511             : }
     512             : 
     513        3734 : int WPXSvInputStreamImpl::seek(long offset)
     514             : {
     515        3734 :     if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
     516           0 :         return -1;
     517             : 
     518        3734 :     sal_Int64 tmpPosition = mxSeekable->getPosition();
     519        3734 :     if ((tmpPosition < 0) || (tmpPosition > LONG_MAX))
     520           0 :         return -1;
     521             : 
     522             :     try
     523             :     {
     524        3734 :         mxSeekable->seek(offset);
     525        3734 :         return 0;
     526             :     }
     527           0 :     catch (...)
     528             :     {
     529             :         SAL_WARN("writerperfect", "mxSeekable->seek(offset) threw exception");
     530           0 :         return -1;
     531             :     }
     532             : }
     533             : 
     534     5744186 : bool WPXSvInputStreamImpl::isEnd()
     535             : {
     536     5744186 :     if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
     537           0 :         return true;
     538     5744186 :     return (mxSeekable->getPosition() >= mnLength);
     539             : }
     540             : 
     541         624 : bool WPXSvInputStreamImpl::isStructured()
     542             : {
     543         624 :     if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
     544           0 :         return false;
     545             : 
     546         624 :     PositionHolder pos(mxSeekable);
     547         624 :     mxSeekable->seek(0);
     548             : 
     549         624 :     if (isOLE())
     550         192 :         return true;
     551             : 
     552         432 :     mxSeekable->seek(0);
     553             : 
     554         432 :     return isZip();
     555             : }
     556             : 
     557          64 : unsigned WPXSvInputStreamImpl::subStreamCount()
     558             : {
     559          64 :     if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
     560           0 :         return 0;
     561             : 
     562          64 :     PositionHolder pos(mxSeekable);
     563          64 :     mxSeekable->seek(0);
     564             : 
     565          64 :     if (isOLE())
     566             :     {
     567          36 :         ensureOLEIsInitialized();
     568             : 
     569          36 :         return mpOLEStorage->maStreams.size();
     570             :     }
     571             : 
     572          28 :     mxSeekable->seek(0);
     573             : 
     574          28 :     if (isZip())
     575             :     {
     576          26 :         ensureZipIsInitialized();
     577             : 
     578          26 :         return mpZipStorage->maStreams.size();
     579             :     }
     580             : 
     581           2 :     return 0;
     582             : }
     583             : 
     584          68 : const char *WPXSvInputStreamImpl::subStreamName(const unsigned id)
     585             : {
     586          68 :     if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
     587           0 :         return 0;
     588             : 
     589          68 :     PositionHolder pos(mxSeekable);
     590          68 :     mxSeekable->seek(0);
     591             : 
     592          68 :     if (isOLE())
     593             :     {
     594          64 :         ensureOLEIsInitialized();
     595             : 
     596          64 :         if (mpOLEStorage->maStreams.size() <= id)
     597           0 :             return 0;
     598             : 
     599          64 :         return mpOLEStorage->maStreams[id].name.getStr();
     600             :     }
     601             : 
     602           4 :     mxSeekable->seek(0);
     603             : 
     604           4 :     if (isZip())
     605             :     {
     606           2 :         ensureZipIsInitialized();
     607             : 
     608           2 :         if (mpZipStorage->maStreams.size() <= id)
     609           0 :             return 0;
     610             : 
     611           2 :         return mpZipStorage->maStreams[id].aName.getStr();
     612             :     }
     613             : 
     614           2 :     return 0;
     615             : }
     616             : 
     617          60 : bool WPXSvInputStreamImpl::existsSubStream(const char *const name)
     618             : {
     619          60 :     if (!name)
     620           0 :         return false;
     621             : 
     622          60 :     if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
     623           0 :         return false;
     624             : 
     625          60 :     PositionHolder pos(mxSeekable);
     626          60 :     mxSeekable->seek(0);
     627             : 
     628         120 :     const rtl::OUString aName(rtl::OStringToOUString(rtl::OString(name), RTL_TEXTENCODING_UTF8));
     629             : 
     630          60 :     if (isOLE())
     631             :     {
     632           4 :         ensureOLEIsInitialized();
     633           4 :         return mpOLEStorage->maNameMap.end() != mpOLEStorage->maNameMap.find(aName);
     634             :     }
     635             : 
     636          56 :     mxSeekable->seek(0);
     637             : 
     638          56 :     if (isZip())
     639             :     {
     640          54 :         ensureZipIsInitialized();
     641          54 :         return mpZipStorage->maNameMap.end() != mpZipStorage->maNameMap.find(aName);
     642             :     }
     643             : 
     644          62 :     return false;
     645             : }
     646             : 
     647         218 : librevenge::RVNGInputStream *WPXSvInputStreamImpl::getSubStreamByName(const char *const name)
     648             : {
     649         218 :     if (!name)
     650           0 :         return 0;
     651             : 
     652         218 :     if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
     653           0 :         return 0;
     654             : 
     655         218 :     PositionHolder pos(mxSeekable);
     656         218 :     mxSeekable->seek(0);
     657             : 
     658         436 :     const rtl::OUString aName(rtl::OStringToOUString(rtl::OString(name), RTL_TEXTENCODING_UTF8));
     659             : 
     660         218 :     if (isOLE())
     661             :     {
     662         166 :         ensureOLEIsInitialized();
     663         166 :         return createWPXStream(mpOLEStorage->getStream(aName));
     664             :     }
     665             : 
     666          52 :     mxSeekable->seek(0);
     667             : 
     668          52 :     if (isZip())
     669             :     {
     670          50 :         ensureZipIsInitialized();
     671             : 
     672             :         try
     673             :         {
     674          50 :             return createWPXStream(mpZipStorage->getStream(aName));
     675             :         }
     676           0 :         catch (const Exception &)
     677             :         {
     678             :             // nothing needed
     679             :         }
     680             :     }
     681             : 
     682         220 :     return 0;
     683             : }
     684             : 
     685          32 : librevenge::RVNGInputStream *WPXSvInputStreamImpl::getSubStreamById(const unsigned id)
     686             : {
     687          32 :     if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
     688           0 :         return 0;
     689             : 
     690          32 :     PositionHolder pos(mxSeekable);
     691          32 :     mxSeekable->seek(0);
     692             : 
     693          32 :     if (isOLE())
     694             :     {
     695           6 :         ensureOLEIsInitialized();
     696             : 
     697           6 :         if (mpOLEStorage->maStreams.size() <= id)
     698           2 :             return 0;
     699             : 
     700           4 :         return createWPXStream(mpOLEStorage->getStream(id));
     701             :     }
     702             : 
     703          26 :     mxSeekable->seek(0);
     704             : 
     705          26 :     if (isZip())
     706             :     {
     707          24 :         ensureZipIsInitialized();
     708             : 
     709          24 :         if (mpZipStorage->maStreams.size() <= id)
     710           2 :             return 0;
     711             : 
     712             :         try
     713             :         {
     714          22 :             return createWPXStream(mpZipStorage->getStream(id));
     715             :         }
     716           0 :         catch (const Exception &)
     717             :         {
     718             :             // nothing needed
     719             :         }
     720             :     }
     721           2 :     return 0;
     722             : }
     723             : 
     724        4258 : void WPXSvInputStreamImpl::invalidateReadBuffer()
     725             : {
     726        4258 :     if (mpReadBuffer)
     727             :     {
     728         654 :         seek((long) tell() + (long)mnReadBufferPos - (long)mnReadBufferLength);
     729         654 :         mpReadBuffer = 0;
     730         654 :         mnReadBufferPos = 0;
     731         654 :         mnReadBufferLength = 0;
     732             :     }
     733        4258 : }
     734             : 
     735         170 : librevenge::RVNGInputStream *WPXSvInputStreamImpl::createWPXStream(const SotStorageStreamRef &rxStorage)
     736             : {
     737         170 :     if (rxStorage.Is())
     738             :     {
     739         158 :         Reference < XInputStream > xContents(new utl::OSeekableInputStreamWrapper(rxStorage));
     740         158 :         return new WPXSvInputStream(xContents);
     741             :     }
     742          12 :     return 0;
     743             : }
     744             : 
     745          72 : librevenge::RVNGInputStream *WPXSvInputStreamImpl::createWPXStream(const Reference<XInputStream> &rxStream)
     746             : {
     747          72 :     if (rxStream.is())
     748          66 :         return new WPXSvInputStream(rxStream);
     749             :     else
     750           6 :         return 0;
     751             : }
     752             : 
     753        1066 : bool WPXSvInputStreamImpl::isOLE()
     754             : {
     755        1066 :     if (!mbCheckedOLE)
     756             :     {
     757             :         assert(0 == mxSeekable->getPosition());
     758             : 
     759         446 :         boost::scoped_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(mxStream));
     760         446 :         if (pStream && SotStorage::IsOLEStorage(pStream.get()))
     761          58 :             mpOLEStorage.reset(new OLEStorageImpl());
     762             : 
     763         446 :         mbCheckedOLE = true;
     764             :     }
     765             : 
     766        1066 :     return bool(mpOLEStorage);
     767             : }
     768             : 
     769         598 : bool WPXSvInputStreamImpl::isZip()
     770             : {
     771         598 :     if (!mbCheckedZip)
     772             :     {
     773             :         assert(0 == mxSeekable->getPosition());
     774             : 
     775             :         try
     776             :         {
     777         388 :             Sequence<Any> aArgs(1);
     778         388 :             aArgs[0] <<= mxStream;
     779             : 
     780         776 :             const Reference<XComponentContext> xContext(comphelper::getProcessComponentContext(), UNO_QUERY_THROW);
     781             :             const Reference<packages::zip::XZipFileAccess2> xZip(
     782         776 :                 xContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.packages.zip.ZipFileAccess", aArgs, xContext),
     783         416 :                 UNO_QUERY_THROW);
     784         416 :             mpZipStorage.reset(new ZipStorageImpl(xZip));
     785             :         }
     786         360 :         catch (const Exception &)
     787             :         {
     788             :             // ignore
     789             :         }
     790             : 
     791         388 :         mbCheckedZip = true;
     792             :     }
     793             : 
     794         598 :     return bool(mpZipStorage);
     795             : }
     796             : 
     797         276 : void WPXSvInputStreamImpl::ensureOLEIsInitialized()
     798             : {
     799             :     assert(mpOLEStorage);
     800             : 
     801         276 :     if (!mpOLEStorage->mbInitialized)
     802          58 :         mpOLEStorage->initialize(utl::UcbStreamHelper::CreateStream(mxStream));
     803         276 : }
     804             : 
     805         156 : void WPXSvInputStreamImpl::ensureZipIsInitialized()
     806             : {
     807             :     assert(mpZipStorage);
     808             : 
     809         156 :     if (!mpZipStorage->mbInitialized)
     810          28 :         mpZipStorage->initialize();
     811         156 : }
     812             : 
     813         698 : WPXSvInputStream::WPXSvInputStream(Reference< XInputStream > xStream) :
     814         698 :     mpImpl(new WPXSvInputStreamImpl(xStream))
     815             : {
     816         698 : }
     817             : 
     818        1652 : WPXSvInputStream::~WPXSvInputStream()
     819             : {
     820         696 :     if (mpImpl)
     821         696 :         delete mpImpl;
     822         956 : }
     823             : 
     824             : #define BUFFER_MAX 65536
     825             : 
     826     3784816 : const unsigned char *WPXSvInputStream::read(unsigned long numBytes, unsigned long &numBytesRead)
     827             : {
     828     3784816 :     numBytesRead = 0;
     829             : 
     830     3784816 :     if (numBytes == 0 || numBytes > (std::numeric_limits<unsigned long>::max)()/2)
     831          70 :         return 0;
     832             : 
     833     3784746 :     if (mpImpl->mpReadBuffer)
     834             :     {
     835     3783702 :         if ((mpImpl->mnReadBufferPos + numBytes > mpImpl->mnReadBufferPos) && (mpImpl->mnReadBufferPos + numBytes <= mpImpl->mnReadBufferLength))
     836             :         {
     837     3783590 :             const unsigned char *pTmp = mpImpl->mpReadBuffer + mpImpl->mnReadBufferPos;
     838     3783590 :             mpImpl->mnReadBufferPos += numBytes;
     839     3783590 :             numBytesRead = numBytes;
     840     3783590 :             return pTmp;
     841             :         }
     842             : 
     843         112 :         mpImpl->invalidateReadBuffer();
     844             :     }
     845             : 
     846        1156 :     unsigned long curpos = (unsigned long) mpImpl->tell();
     847        1156 :     if (curpos == (unsigned long)-1)  // returned ERROR
     848           0 :         return 0;
     849             : 
     850        2312 :     if ((curpos + numBytes < curpos) /*overflow*/ ||
     851        1156 :             (curpos + numBytes >= (sal_uInt64)mpImpl->mnLength))  /*reading more than available*/
     852             :     {
     853          68 :         numBytes = mpImpl->mnLength - curpos;
     854             :     }
     855             : 
     856        1156 :     if (numBytes < BUFFER_MAX)
     857             :     {
     858        1136 :         if (BUFFER_MAX < mpImpl->mnLength - curpos)
     859         194 :             mpImpl->mnReadBufferLength = BUFFER_MAX;
     860             :         else /* BUFFER_MAX >= mpImpl->mnLength - curpos */
     861         942 :             mpImpl->mnReadBufferLength = mpImpl->mnLength - curpos;
     862             :     }
     863             :     else
     864          20 :         mpImpl->mnReadBufferLength = numBytes;
     865             : 
     866        1156 :     unsigned long tmpNumBytes(0);
     867        1156 :     mpImpl->mpReadBuffer = mpImpl->read(mpImpl->mnReadBufferLength, tmpNumBytes);
     868        1156 :     if (tmpNumBytes != mpImpl->mnReadBufferLength)
     869           0 :         mpImpl->mnReadBufferLength = tmpNumBytes;
     870             : 
     871        1156 :     mpImpl->mnReadBufferPos = 0;
     872        1156 :     if (!mpImpl->mnReadBufferLength)
     873          14 :         return 0;
     874             : 
     875        1142 :     numBytesRead = numBytes;
     876             : 
     877        1142 :     mpImpl->mnReadBufferPos += numBytesRead;
     878        1142 :     return mpImpl->mpReadBuffer;
     879             : }
     880             : 
     881     2545750 : long WPXSvInputStream::tell()
     882             : {
     883     2545750 :     long retVal = mpImpl->tell();
     884     2545750 :     return retVal - (long)mpImpl->mnReadBufferLength + (long)mpImpl->mnReadBufferPos;
     885             : }
     886             : 
     887      114756 : int WPXSvInputStream::seek(long offset, librevenge::RVNG_SEEK_TYPE seekType)
     888             : {
     889      114756 :     sal_Int64 tmpOffset = offset;
     890      114756 :     if (seekType == librevenge::RVNG_SEEK_CUR)
     891         992 :         tmpOffset += tell();
     892      114756 :     if (seekType == librevenge::RVNG_SEEK_END)
     893         520 :         tmpOffset += mpImpl->mnLength;
     894             : 
     895      114756 :     int retVal = 0;
     896      114756 :     if (tmpOffset < 0)
     897             :     {
     898           6 :         tmpOffset = 0;
     899           6 :         retVal = -1;
     900             :     }
     901      114756 :     if (tmpOffset > mpImpl->mnLength)
     902             :     {
     903          30 :         tmpOffset = mpImpl->mnLength;
     904          30 :         retVal = -1;
     905             :     }
     906             : 
     907      114756 :     if (tmpOffset < mpImpl->tell() && (unsigned long)tmpOffset >= (unsigned long)mpImpl->tell() - mpImpl->mnReadBufferLength)
     908             :     {
     909      111676 :         mpImpl->mnReadBufferPos = (unsigned long)(tmpOffset + (long) mpImpl->mnReadBufferLength - (long) mpImpl->tell());
     910      111676 :         return retVal;
     911             :     }
     912             : 
     913        3080 :     mpImpl->invalidateReadBuffer();
     914             : 
     915        3080 :     if (mpImpl->seek(tmpOffset))
     916           0 :         return -1;
     917        3080 :     return retVal;
     918             : }
     919             : 
     920     5743044 : bool WPXSvInputStream::isEnd()
     921             : {
     922     5743044 :     return mpImpl->isEnd() && mpImpl->mnReadBufferPos == mpImpl->mnReadBufferLength;
     923             : }
     924             : 
     925         624 : bool WPXSvInputStream::isStructured()
     926             : {
     927         624 :     mpImpl->invalidateReadBuffer();
     928         624 :     return mpImpl->isStructured();
     929             : }
     930             : 
     931          64 : unsigned WPXSvInputStream::subStreamCount()
     932             : {
     933          64 :     mpImpl->invalidateReadBuffer();
     934          64 :     return mpImpl->subStreamCount();
     935             : }
     936             : 
     937          68 : const char *WPXSvInputStream::subStreamName(const unsigned id)
     938             : {
     939          68 :     mpImpl->invalidateReadBuffer();
     940          68 :     return mpImpl->subStreamName(id);
     941             : }
     942             : 
     943          60 : bool WPXSvInputStream::existsSubStream(const char *const name)
     944             : {
     945          60 :     mpImpl->invalidateReadBuffer();
     946          60 :     return mpImpl->existsSubStream(name);
     947             : }
     948             : 
     949         218 : librevenge::RVNGInputStream *WPXSvInputStream::getSubStreamByName(const char *name)
     950             : {
     951         218 :     mpImpl->invalidateReadBuffer();
     952         218 :     return mpImpl->getSubStreamByName(name);
     953             : }
     954             : 
     955          32 : librevenge::RVNGInputStream *WPXSvInputStream::getSubStreamById(const unsigned id)
     956             : {
     957          32 :     mpImpl->invalidateReadBuffer();
     958          32 :     return mpImpl->getSubStreamById(id);
     959             : }
     960             : 
     961             : }
     962             : 
     963             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10