Bump version to 5.0-14
[LibreOffice.git] / writerperfect / source / common / WPXSvInputStream.cxx
blobe0fff43199d19b387b1b7da3725314c731937271
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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 */
10 #include <WPXSvInputStream.hxx>
12 #include <com/sun/star/packages/zip/XZipFileAccess2.hpp>
13 #include <com/sun/star/uno/Any.hxx>
15 #include <comphelper/processfactory.hxx>
16 #include <comphelper/seekableinput.hxx>
18 #include <rtl/string.hxx>
20 #include <sot/storage.hxx>
22 #include <tools/stream.hxx>
23 #include <unotools/streamwrap.hxx>
24 #include <unotools/ucbstreamhelper.hxx>
26 #include <limits>
27 #include <vector>
29 #include <boost/noncopyable.hpp>
30 #include <boost/scoped_ptr.hpp>
31 #include <unordered_map>
33 namespace writerperfect
36 using namespace ::com::sun::star::uno;
37 using namespace ::com::sun::star::io;
39 namespace container = com::sun::star::container;
40 namespace lang = com::sun::star::lang;
41 namespace packages = com::sun::star::packages;
43 namespace
46 class PositionHolder : boost::noncopyable
48 public:
49 explicit PositionHolder(const Reference<XSeekable> &rxSeekable);
50 ~PositionHolder();
52 private:
53 const Reference<XSeekable> mxSeekable;
54 const sal_uInt64 mnPosition;
57 PositionHolder::PositionHolder(const Reference<XSeekable> &rxSeekable)
58 : mxSeekable(rxSeekable)
59 , mnPosition(rxSeekable->getPosition())
63 PositionHolder::~PositionHolder() try
65 mxSeekable->seek(mnPosition);
67 catch (...)
71 } // anonymous namespace
73 typedef struct
75 tools::SvRef<SotStorage> ref;
76 } SotStorageRefWrapper;
78 typedef struct
80 tools::SvRef<SotStorageStream> ref;
81 } SotStorageStreamRefWrapper;
83 namespace
86 rtl::OUString lcl_normalizeSubStreamPath(const rtl::OUString &rPath)
88 // accept paths which begin by '/'
89 // TODO: maybe this should to a full normalization
90 if (rPath.startsWith("/") && rPath.getLength() >= 2)
91 return rPath.copy(1);
92 return rPath;
97 namespace
100 const rtl::OUString concatPath(const rtl::OUString &lhs, const rtl::OUString &rhs)
102 if (lhs.isEmpty())
103 return rhs;
104 return lhs + "/" + rhs;
107 struct OLEStreamData
109 explicit OLEStreamData(const rtl::OString &rName);
111 SotStorageStreamRefWrapper stream;
113 /** Name of the stream.
115 * This is not @c rtl::OUString, because we need to be able to
116 * produce const char* from it.
118 rtl::OString name;
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;
124 /** Representation of an OLE2 storage.
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).
137 * Streams are created on demand (and saved, for the same reason as
138 * storages).
140 struct OLEStorageImpl
142 OLEStorageImpl();
144 void initialize(SvStream *pStream);
146 tools::SvRef<SotStorageStream> getStream(const rtl::OUString &rPath);
147 tools::SvRef<SotStorageStream> getStream(std::size_t nId);
149 private:
150 void traverse(const tools::SvRef<SotStorage> &rStorage, const rtl::OUString &rPath);
152 tools::SvRef<SotStorageStream> createStream(const rtl::OUString &rPath);
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;
162 OLEStreamData::OLEStreamData(const rtl::OString &rName)
163 : stream()
164 , name(rName)
168 OLEStorageImpl::OLEStorageImpl()
169 : mxRootStorage()
170 , maStorageMap()
171 , maStreams()
172 , maNameMap()
173 , mbInitialized(false)
177 void OLEStorageImpl::initialize(SvStream *const pStream)
179 if (!pStream)
180 return;
182 mxRootStorage.ref = new SotStorage(pStream, true);
184 traverse(mxRootStorage.ref, "");
186 mbInitialized = true;
189 tools::SvRef<SotStorageStream> OLEStorageImpl::getStream(const rtl::OUString &rPath)
191 const rtl::OUString aPath(lcl_normalizeSubStreamPath(rPath));
192 NameMap_t::iterator aIt = maNameMap.find(aPath);
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 if (maNameMap.end() == aIt)
198 return tools::SvRef<SotStorageStream>();
200 if (!maStreams[aIt->second].stream.ref.Is())
201 maStreams[aIt->second].stream.ref = createStream(aPath);
203 return maStreams[aIt->second].stream.ref;
206 tools::SvRef<SotStorageStream> OLEStorageImpl::getStream(const std::size_t nId)
208 if (!maStreams[nId].stream.ref.Is())
209 maStreams[nId].stream.ref = createStream(rtl::OStringToOUString(maStreams[nId].name, RTL_TEXTENCODING_UTF8));
211 return maStreams[nId].stream.ref;
214 void OLEStorageImpl::traverse(const tools::SvRef<SotStorage> &rStorage, const rtl::OUString &rPath)
216 SvStorageInfoList infos;
218 rStorage->FillInfoList(&infos);
220 for (SvStorageInfoList::const_iterator aIt = infos.begin(); infos.end() != aIt; ++aIt)
222 if (aIt->IsStream())
224 maStreams.push_back(OLEStreamData(rtl::OUStringToOString(concatPath(rPath, aIt->GetName()), RTL_TEXTENCODING_UTF8)));
225 maNameMap[concatPath(rPath, aIt->GetName())] = maStreams.size() - 1;
227 else if (aIt->IsStorage())
229 const rtl::OUString aPath = concatPath(rPath, aIt->GetName());
230 SotStorageRefWrapper xStorage;
231 xStorage.ref = rStorage->OpenSotStorage(aIt->GetName(), STREAM_STD_READ);
232 maStorageMap[aPath] = xStorage;
234 // deep-first traversal
235 traverse(xStorage.ref, aPath);
237 else
239 SAL_WARN("writerperfect", "OLEStorageImpl::traverse: invalid storage entry, neither stream nor file");
244 tools::SvRef<SotStorageStream> OLEStorageImpl::createStream(const rtl::OUString &rPath)
246 const sal_Int32 nDelim = rPath.lastIndexOf(sal_Unicode('/'));
248 if (-1 == nDelim)
249 return mxRootStorage.ref->OpenSotStream(rPath, STREAM_STD_READ);
251 const rtl::OUString aDir = rPath.copy(0, nDelim);
252 const rtl::OUString aName = rPath.copy(nDelim + 1);
254 const OLEStorageMap_t::const_iterator aIt = maStorageMap.find(aDir);
256 if (maStorageMap.end() == aIt)
257 return 0;
259 return aIt->second.ref->OpenSotStream(aName, STREAM_STD_READ);
264 namespace
267 struct ZipStreamData
269 explicit ZipStreamData(const rtl::OString &rName);
271 Reference<XInputStream> xStream;
273 /** Name of the stream.
275 * This is not @c rtl::OUString, because we need to be able to
276 * produce const char* from it.
278 rtl::OString aName;
281 /** Representation of a Zip storage.
283 * This is quite similar to OLEStorageImpl, except that we do not need
284 * to keep all storages (folders) open.
286 struct ZipStorageImpl
288 ZipStorageImpl(const Reference<container::XNameAccess> &rxContainer);
290 /** Initialize for access.
292 * This creates a bidirectional map of stream names to their
293 * indexes (index of a stream is determined by deep-first
294 * traversal).
296 void initialize();
298 Reference<XInputStream> getStream(const rtl::OUString &rPath);
299 Reference<XInputStream> getStream(std::size_t nId);
301 private:
302 void traverse(const Reference<container::XNameAccess> &rxEnum);
304 Reference<XInputStream> createStream(const rtl::OUString &rPath);
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;
313 ZipStreamData::ZipStreamData(const rtl::OString &rName)
314 : xStream()
315 , aName(rName)
319 ZipStorageImpl::ZipStorageImpl(const Reference<container::XNameAccess> &rxContainer)
320 : mxContainer(rxContainer)
321 , maStreams()
322 , maNameMap()
323 , mbInitialized(false)
325 assert(mxContainer.is());
328 void ZipStorageImpl::initialize()
330 traverse(mxContainer);
332 mbInitialized = true;
335 Reference<XInputStream> ZipStorageImpl::getStream(const rtl::OUString &rPath)
337 const rtl::OUString aPath(lcl_normalizeSubStreamPath(rPath));
338 NameMap_t::iterator aIt = maNameMap.find(aPath);
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 if (maNameMap.end() == aIt)
344 return Reference<XInputStream>();
346 if (!maStreams[aIt->second].xStream.is())
347 maStreams[aIt->second].xStream = createStream(aPath);
349 return maStreams[aIt->second].xStream;
352 Reference<XInputStream> ZipStorageImpl::getStream(const std::size_t nId)
354 if (!maStreams[nId].xStream.is())
355 maStreams[nId].xStream = createStream(rtl::OStringToOUString(maStreams[nId].aName, RTL_TEXTENCODING_UTF8));
357 return maStreams[nId].xStream;
360 void ZipStorageImpl::traverse(const Reference<container::XNameAccess> &rxContainer)
362 const Sequence<rtl::OUString> lNames = rxContainer->getElementNames();
364 maStreams.reserve(lNames.getLength());
366 for (sal_Int32 n = 0; n < lNames.getLength(); ++n)
368 if (!lNames[n].endsWith("/")) // skip dirs
370 maStreams.push_back(ZipStreamData(rtl::OUStringToOString(lNames[n], RTL_TEXTENCODING_UTF8)));
371 maNameMap[lNames[n]] = maStreams.size() - 1;
376 Reference<XInputStream> ZipStorageImpl::createStream(const rtl::OUString &rPath)
378 Reference<XInputStream> xStream;
382 const Reference<XInputStream> xInputStream(mxContainer->getByName(rPath), UNO_QUERY_THROW);
383 const Reference<XSeekable> xSeekable(xInputStream, UNO_QUERY);
385 if (xSeekable.is())
386 xStream = xInputStream;
387 else
388 xStream.set(new comphelper::OSeekableInputWrapper(xInputStream, comphelper::getProcessComponentContext()));
390 catch (const Exception &)
392 // nothing needed
395 return xStream;
400 class WPXSvInputStreamImpl
402 public :
403 WPXSvInputStreamImpl(::com::sun::star::uno::Reference<
404 ::com::sun::star::io::XInputStream > xStream);
405 ~WPXSvInputStreamImpl();
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);
414 const unsigned char *read(unsigned long numBytes, unsigned long &numBytesRead);
415 int seek(long offset);
416 long tell();
417 bool isEnd();
419 void invalidateReadBuffer();
421 private:
422 bool isOLE();
423 void ensureOLEIsInitialized();
425 bool isZip();
426 void ensureZipIsInitialized();
428 static librevenge::RVNGInputStream *createWPXStream(const tools::SvRef<SotStorageStream> &rxStorage);
429 static librevenge::RVNGInputStream *createWPXStream(const Reference<XInputStream> &rxStream);
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;
446 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 mnReadBufferPos(0)
459 if (!xStream.is() || !mxStream.is())
460 mnLength = 0;
461 else
463 if (!mxSeekable.is())
464 mnLength = 0;
465 else
469 mnLength = mxSeekable->getLength();
470 if (0 < mxSeekable->getPosition())
471 mxSeekable->seek(0);
473 catch (...)
475 SAL_WARN("writerperfect", "mnLength = mxSeekable->getLength() threw exception");
476 mnLength = 0;
482 WPXSvInputStreamImpl::~WPXSvInputStreamImpl()
486 const unsigned char *WPXSvInputStreamImpl::read(unsigned long numBytes, unsigned long &numBytesRead)
488 numBytesRead = 0;
490 if (numBytes == 0 || isEnd())
491 return 0;
493 numBytesRead = mxStream->readSomeBytes(maData, numBytes);
494 if (numBytesRead == 0)
495 return 0;
497 return reinterpret_cast<const unsigned char *>(maData.getConstArray());
500 long WPXSvInputStreamImpl::tell()
502 if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
503 return -1L;
504 else
506 sal_Int64 tmpPosition = mxSeekable->getPosition();
507 if ((tmpPosition < 0) || (tmpPosition > LONG_MAX))
508 return -1L;
509 return (long)tmpPosition;
513 int WPXSvInputStreamImpl::seek(long offset)
515 if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
516 return -1;
518 sal_Int64 tmpPosition = mxSeekable->getPosition();
519 if ((tmpPosition < 0) || (tmpPosition > LONG_MAX))
520 return -1;
524 mxSeekable->seek(offset);
525 return 0;
527 catch (...)
529 SAL_WARN("writerperfect", "mxSeekable->seek(offset) threw exception");
530 return -1;
534 bool WPXSvInputStreamImpl::isEnd()
536 if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
537 return true;
538 return (mxSeekable->getPosition() >= mnLength);
541 bool WPXSvInputStreamImpl::isStructured()
543 if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
544 return false;
546 PositionHolder pos(mxSeekable);
547 mxSeekable->seek(0);
549 if (isOLE())
550 return true;
552 mxSeekable->seek(0);
554 return isZip();
557 unsigned WPXSvInputStreamImpl::subStreamCount()
559 if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
560 return 0;
562 PositionHolder pos(mxSeekable);
563 mxSeekable->seek(0);
565 if (isOLE())
567 ensureOLEIsInitialized();
569 return mpOLEStorage->maStreams.size();
572 mxSeekable->seek(0);
574 if (isZip())
576 ensureZipIsInitialized();
578 return mpZipStorage->maStreams.size();
581 return 0;
584 const char *WPXSvInputStreamImpl::subStreamName(const unsigned id)
586 if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
587 return 0;
589 PositionHolder pos(mxSeekable);
590 mxSeekable->seek(0);
592 if (isOLE())
594 ensureOLEIsInitialized();
596 if (mpOLEStorage->maStreams.size() <= id)
597 return 0;
599 return mpOLEStorage->maStreams[id].name.getStr();
602 mxSeekable->seek(0);
604 if (isZip())
606 ensureZipIsInitialized();
608 if (mpZipStorage->maStreams.size() <= id)
609 return 0;
611 return mpZipStorage->maStreams[id].aName.getStr();
614 return 0;
617 bool WPXSvInputStreamImpl::existsSubStream(const char *const name)
619 if (!name)
620 return false;
622 if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
623 return false;
625 PositionHolder pos(mxSeekable);
626 mxSeekable->seek(0);
628 const rtl::OUString aName(rtl::OStringToOUString(rtl::OString(name), RTL_TEXTENCODING_UTF8));
630 if (isOLE())
632 ensureOLEIsInitialized();
633 return mpOLEStorage->maNameMap.end() != mpOLEStorage->maNameMap.find(aName);
636 mxSeekable->seek(0);
638 if (isZip())
640 ensureZipIsInitialized();
641 return mpZipStorage->maNameMap.end() != mpZipStorage->maNameMap.find(aName);
644 return false;
647 librevenge::RVNGInputStream *WPXSvInputStreamImpl::getSubStreamByName(const char *const name)
649 if (!name)
650 return 0;
652 if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
653 return 0;
655 PositionHolder pos(mxSeekable);
656 mxSeekable->seek(0);
658 const rtl::OUString aName(rtl::OStringToOUString(rtl::OString(name), RTL_TEXTENCODING_UTF8));
660 if (isOLE())
662 ensureOLEIsInitialized();
663 return createWPXStream(mpOLEStorage->getStream(aName));
666 mxSeekable->seek(0);
668 if (isZip())
670 ensureZipIsInitialized();
674 return createWPXStream(mpZipStorage->getStream(aName));
676 catch (const Exception &)
678 // nothing needed
682 return 0;
685 librevenge::RVNGInputStream *WPXSvInputStreamImpl::getSubStreamById(const unsigned id)
687 if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
688 return 0;
690 PositionHolder pos(mxSeekable);
691 mxSeekable->seek(0);
693 if (isOLE())
695 ensureOLEIsInitialized();
697 if (mpOLEStorage->maStreams.size() <= id)
698 return 0;
700 return createWPXStream(mpOLEStorage->getStream(id));
703 mxSeekable->seek(0);
705 if (isZip())
707 ensureZipIsInitialized();
709 if (mpZipStorage->maStreams.size() <= id)
710 return 0;
714 return createWPXStream(mpZipStorage->getStream(id));
716 catch (const Exception &)
718 // nothing needed
721 return 0;
724 void WPXSvInputStreamImpl::invalidateReadBuffer()
726 if (mpReadBuffer)
728 seek((long) tell() + (long)mnReadBufferPos - (long)mnReadBufferLength);
729 mpReadBuffer = 0;
730 mnReadBufferPos = 0;
731 mnReadBufferLength = 0;
735 librevenge::RVNGInputStream *WPXSvInputStreamImpl::createWPXStream(const tools::SvRef<SotStorageStream> &rxStorage)
737 if (rxStorage.Is())
739 Reference < XInputStream > xContents(new utl::OSeekableInputStreamWrapper(rxStorage));
740 return new WPXSvInputStream(xContents);
742 return 0;
745 librevenge::RVNGInputStream *WPXSvInputStreamImpl::createWPXStream(const Reference<XInputStream> &rxStream)
747 if (rxStream.is())
748 return new WPXSvInputStream(rxStream);
749 else
750 return 0;
753 bool WPXSvInputStreamImpl::isOLE()
755 if (!mbCheckedOLE)
757 assert(0 == mxSeekable->getPosition());
759 boost::scoped_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(mxStream));
760 if (pStream && SotStorage::IsOLEStorage(pStream.get()))
761 mpOLEStorage.reset(new OLEStorageImpl());
763 mbCheckedOLE = true;
766 return bool(mpOLEStorage);
769 bool WPXSvInputStreamImpl::isZip()
771 if (!mbCheckedZip)
773 assert(0 == mxSeekable->getPosition());
777 Sequence<Any> aArgs(1);
778 aArgs[0] <<= mxStream;
780 const Reference<XComponentContext> xContext(comphelper::getProcessComponentContext(), UNO_QUERY_THROW);
781 const Reference<packages::zip::XZipFileAccess2> xZip(
782 xContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.packages.zip.ZipFileAccess", aArgs, xContext),
783 UNO_QUERY_THROW);
784 mpZipStorage.reset(new ZipStorageImpl(xZip));
786 catch (const Exception &)
788 // ignore
791 mbCheckedZip = true;
794 return bool(mpZipStorage);
797 void WPXSvInputStreamImpl::ensureOLEIsInitialized()
799 assert(mpOLEStorage);
801 if (!mpOLEStorage->mbInitialized)
802 mpOLEStorage->initialize(utl::UcbStreamHelper::CreateStream(mxStream));
805 void WPXSvInputStreamImpl::ensureZipIsInitialized()
807 assert(mpZipStorage);
809 if (!mpZipStorage->mbInitialized)
810 mpZipStorage->initialize();
813 WPXSvInputStream::WPXSvInputStream(Reference< XInputStream > xStream) :
814 mpImpl(new WPXSvInputStreamImpl(xStream))
818 WPXSvInputStream::~WPXSvInputStream()
820 if (mpImpl)
821 delete mpImpl;
824 #define BUFFER_MAX 65536
826 const unsigned char *WPXSvInputStream::read(unsigned long numBytes, unsigned long &numBytesRead)
828 numBytesRead = 0;
830 if (numBytes == 0 || numBytes > (std::numeric_limits<unsigned long>::max)()/2)
831 return 0;
833 if (mpImpl->mpReadBuffer)
835 if ((mpImpl->mnReadBufferPos + numBytes > mpImpl->mnReadBufferPos) && (mpImpl->mnReadBufferPos + numBytes <= mpImpl->mnReadBufferLength))
837 const unsigned char *pTmp = mpImpl->mpReadBuffer + mpImpl->mnReadBufferPos;
838 mpImpl->mnReadBufferPos += numBytes;
839 numBytesRead = numBytes;
840 return pTmp;
843 mpImpl->invalidateReadBuffer();
846 unsigned long curpos = (unsigned long) mpImpl->tell();
847 if (curpos == (unsigned long)-1) // returned ERROR
848 return 0;
850 if ((curpos + numBytes < curpos) /*overflow*/ ||
851 (curpos + numBytes >= (sal_uInt64)mpImpl->mnLength)) /*reading more than available*/
853 numBytes = mpImpl->mnLength - curpos;
856 if (numBytes < BUFFER_MAX)
858 if (BUFFER_MAX < mpImpl->mnLength - curpos)
859 mpImpl->mnReadBufferLength = BUFFER_MAX;
860 else /* BUFFER_MAX >= mpImpl->mnLength - curpos */
861 mpImpl->mnReadBufferLength = mpImpl->mnLength - curpos;
863 else
864 mpImpl->mnReadBufferLength = numBytes;
866 unsigned long tmpNumBytes(0);
867 mpImpl->mpReadBuffer = mpImpl->read(mpImpl->mnReadBufferLength, tmpNumBytes);
868 if (tmpNumBytes != mpImpl->mnReadBufferLength)
869 mpImpl->mnReadBufferLength = tmpNumBytes;
871 mpImpl->mnReadBufferPos = 0;
872 if (!mpImpl->mnReadBufferLength)
873 return 0;
875 numBytesRead = numBytes;
877 mpImpl->mnReadBufferPos += numBytesRead;
878 return mpImpl->mpReadBuffer;
881 long WPXSvInputStream::tell()
883 long retVal = mpImpl->tell();
884 return retVal - (long)mpImpl->mnReadBufferLength + (long)mpImpl->mnReadBufferPos;
887 int WPXSvInputStream::seek(long offset, librevenge::RVNG_SEEK_TYPE seekType)
889 sal_Int64 tmpOffset = offset;
890 if (seekType == librevenge::RVNG_SEEK_CUR)
891 tmpOffset += tell();
892 if (seekType == librevenge::RVNG_SEEK_END)
893 tmpOffset += mpImpl->mnLength;
895 int retVal = 0;
896 if (tmpOffset < 0)
898 tmpOffset = 0;
899 retVal = -1;
901 if (tmpOffset > mpImpl->mnLength)
903 tmpOffset = mpImpl->mnLength;
904 retVal = -1;
907 if (tmpOffset < mpImpl->tell() && (unsigned long)tmpOffset >= (unsigned long)mpImpl->tell() - mpImpl->mnReadBufferLength)
909 mpImpl->mnReadBufferPos = (unsigned long)(tmpOffset + (long) mpImpl->mnReadBufferLength - (long) mpImpl->tell());
910 return retVal;
913 mpImpl->invalidateReadBuffer();
915 if (mpImpl->seek(tmpOffset))
916 return -1;
917 return retVal;
920 bool WPXSvInputStream::isEnd()
922 return mpImpl->isEnd() && mpImpl->mnReadBufferPos == mpImpl->mnReadBufferLength;
925 bool WPXSvInputStream::isStructured()
927 mpImpl->invalidateReadBuffer();
928 return mpImpl->isStructured();
931 unsigned WPXSvInputStream::subStreamCount()
933 mpImpl->invalidateReadBuffer();
934 return mpImpl->subStreamCount();
937 const char *WPXSvInputStream::subStreamName(const unsigned id)
939 mpImpl->invalidateReadBuffer();
940 return mpImpl->subStreamName(id);
943 bool WPXSvInputStream::existsSubStream(const char *const name)
945 mpImpl->invalidateReadBuffer();
946 return mpImpl->existsSubStream(name);
949 librevenge::RVNGInputStream *WPXSvInputStream::getSubStreamByName(const char *name)
951 mpImpl->invalidateReadBuffer();
952 return mpImpl->getSubStreamByName(name);
955 librevenge::RVNGInputStream *WPXSvInputStream::getSubStreamById(const unsigned id)
957 mpImpl->invalidateReadBuffer();
958 return mpImpl->getSubStreamById(id);
963 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */