loplugin:returnconstval in writerperfect
[LibreOffice.git] / writerperfect / source / common / WPXSvInputStream.cxx
blobf1799f56bd198eed65f6a67cbec2bcef613debd8
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/XComponentContext.hpp>
15 #include <comphelper/processfactory.hxx>
16 #include <comphelper/seekableinput.hxx>
18 #include <rtl/string.hxx>
19 #include <sal/log.hxx>
21 #include <sot/storage.hxx>
23 #include <tools/stream.hxx>
24 #include <unotools/streamwrap.hxx>
25 #include <unotools/ucbstreamhelper.hxx>
27 #include <climits>
28 #include <limits>
29 #include <memory>
30 #include <unordered_map>
31 #include <vector>
33 namespace writerperfect
35 using namespace ::com::sun::star::uno;
36 using namespace ::com::sun::star::io;
38 namespace container = com::sun::star::container;
39 namespace packages = com::sun::star::packages;
41 namespace
43 class PositionHolder
45 public:
46 explicit PositionHolder(const Reference<XSeekable>& rxSeekable);
47 ~PositionHolder();
48 PositionHolder(const PositionHolder&) = delete;
49 PositionHolder& operator=(const PositionHolder&) = delete;
51 private:
52 const Reference<XSeekable> mxSeekable;
53 const sal_uInt64 mnPosition;
56 PositionHolder::PositionHolder(const Reference<XSeekable>& rxSeekable)
57 : mxSeekable(rxSeekable)
58 , mnPosition(rxSeekable->getPosition())
62 PositionHolder::~PositionHolder()
64 try
66 mxSeekable->seek(mnPosition);
68 catch (...)
73 } // anonymous namespace
75 namespace
77 OUString lcl_normalizeSubStreamPath(const OUString& rPath)
79 // accept paths which begin by '/'
80 // TODO: maybe this should to a full normalization
81 if (rPath.startsWith("/") && rPath.getLength() >= 2)
82 return rPath.copy(1);
83 return rPath;
87 namespace
89 OUString concatPath(const OUString& lhs, const OUString& rhs)
91 if (lhs.isEmpty())
92 return rhs;
93 return lhs + "/" + rhs;
96 struct OLEStreamData
98 OLEStreamData(const OString& rName, const OString& rvngName);
100 tools::SvRef<SotStorageStream> stream;
102 /** Name of the stream.
104 * This is not @c OUString, because we need to be able to
105 * produce const char* from it.
107 OString const name;
108 /** librevenge name of the stream.
110 * This is not @c OUString, because we need to be able to
111 * produce const char* from it.
113 OString const RVNGname;
116 typedef std::unordered_map<OUString, std::size_t> NameMap_t;
117 typedef std::unordered_map<OUString, tools::SvRef<SotStorage>> OLEStorageMap_t;
119 /** Representation of an OLE2 storage.
121 * This class tries to bring a bit of sanity to use of SotStorage with
122 * respect to the needs of @c librevenge::RVNGInputStream API. It
123 * holds all nested storages for the whole lifetime (more precisely,
124 * since initialization, which is performed by calling @c
125 * initialize()), thus ensuring that no created stream is destroyed
126 * just because its parent storage went out of scope. It also holds a
127 * bidirectional map of stream names to their indexes (index of a
128 * stream is determined by deep-first traversal), which is also
129 * populated during initialization (member variables @c maStreams and
130 * @c maNameMap).
132 * Streams are created on demand (and saved, for the same reason as
133 * storages).
135 struct OLEStorageImpl
137 OLEStorageImpl();
139 void initialize(std::unique_ptr<SvStream> pStream);
141 tools::SvRef<SotStorageStream> getStream(const OUString& rPath);
142 tools::SvRef<SotStorageStream> const& getStream(std::size_t nId);
144 private:
145 void traverse(const tools::SvRef<SotStorage>& rStorage, const OUString& rPath);
147 tools::SvRef<SotStorageStream> createStream(const OUString& rPath);
149 public:
150 tools::SvRef<SotStorage> mxRootStorage; //< root storage of the OLE2
151 OLEStorageMap_t maStorageMap; //< map of all sub storages by name
152 ::std::vector<OLEStreamData> maStreams; //< list of streams and their names
153 NameMap_t maNameMap; //< map of stream names to indexes (into @c maStreams)
154 bool mbInitialized;
157 OLEStreamData::OLEStreamData(const OString& rName, const OString& rvngName)
158 : stream()
159 , name(rName)
160 , RVNGname(rvngName)
164 OLEStorageImpl::OLEStorageImpl()
165 : mxRootStorage()
166 , maStorageMap()
167 , maStreams()
168 , maNameMap()
169 , mbInitialized(false)
173 void OLEStorageImpl::initialize(std::unique_ptr<SvStream> pStream)
175 if (!pStream)
176 return;
178 mxRootStorage = new SotStorage(pStream.release(), true);
180 traverse(mxRootStorage, "");
182 mbInitialized = true;
185 tools::SvRef<SotStorageStream> OLEStorageImpl::getStream(const OUString& rPath)
187 const OUString aPath(lcl_normalizeSubStreamPath(rPath));
188 NameMap_t::iterator aIt = maNameMap.find(aPath);
190 // For the while don't return stream in this situation.
191 // Later, given how libcdr's zip stream implementation behaves,
192 // return the first stream in the storage if there is one.
193 if (maNameMap.end() == aIt)
194 return tools::SvRef<SotStorageStream>();
196 if (!maStreams[aIt->second].stream.is())
197 maStreams[aIt->second].stream
198 = createStream(OStringToOUString(maStreams[aIt->second].name, RTL_TEXTENCODING_UTF8));
200 return maStreams[aIt->second].stream;
203 tools::SvRef<SotStorageStream> const& OLEStorageImpl::getStream(const std::size_t nId)
205 if (!maStreams[nId].stream.is())
206 maStreams[nId].stream
207 = createStream(OStringToOUString(maStreams[nId].name, RTL_TEXTENCODING_UTF8));
209 return maStreams[nId].stream;
212 void OLEStorageImpl::traverse(const tools::SvRef<SotStorage>& rStorage, const OUString& rPath)
214 SvStorageInfoList infos;
216 rStorage->FillInfoList(&infos);
218 for (const auto& info : infos)
220 if (info.IsStream())
222 OUString baseName = info.GetName(), rvngName = baseName;
223 // librevenge::RVNGOLEStream ignores the first character when is a control code, so ...
224 if (!rvngName.isEmpty() && rvngName.toChar() < 32)
225 rvngName = rvngName.copy(1);
226 maStreams.emplace_back(
227 OUStringToOString(concatPath(rPath, baseName), RTL_TEXTENCODING_UTF8),
228 OUStringToOString(concatPath(rPath, rvngName), RTL_TEXTENCODING_UTF8));
229 maNameMap[concatPath(rPath, rvngName)] = maStreams.size() - 1;
231 else if (info.IsStorage())
233 const OUString aPath = concatPath(rPath, info.GetName());
234 tools::SvRef<SotStorage> aStorage
235 = rStorage->OpenSotStorage(info.GetName(), StreamMode::STD_READ);
236 maStorageMap[aPath] = aStorage;
238 // deep-first traversal
239 traverse(aStorage, aPath);
241 else
243 SAL_WARN("writerperfect",
244 "OLEStorageImpl::traverse: invalid storage entry, neither stream nor file");
249 tools::SvRef<SotStorageStream> OLEStorageImpl::createStream(const OUString& rPath)
251 const sal_Int32 nDelim = rPath.lastIndexOf(u'/');
253 if (-1 == nDelim)
254 return mxRootStorage->OpenSotStream(rPath, StreamMode::STD_READ);
256 const OUString aDir = rPath.copy(0, nDelim);
257 const OUString aName = rPath.copy(nDelim + 1);
259 const OLEStorageMap_t::const_iterator aIt = maStorageMap.find(aDir);
261 if (maStorageMap.end() == aIt)
262 return nullptr;
264 return aIt->second->OpenSotStream(aName, StreamMode::STD_READ);
268 namespace
270 struct ZipStreamData
272 explicit ZipStreamData(const OString& rName);
274 Reference<XInputStream> xStream;
276 /** Name of the stream.
278 * This is not @c OUString, because we need to be able to
279 * produce const char* from it.
281 OString const aName;
284 /** Representation of a Zip storage.
286 * This is quite similar to OLEStorageImpl, except that we do not need
287 * to keep all storages (folders) open.
289 struct ZipStorageImpl
291 explicit ZipStorageImpl(const Reference<container::XNameAccess>& rxContainer);
293 /** Initialize for access.
295 * This creates a bidirectional map of stream names to their
296 * indexes (index of a stream is determined by deep-first
297 * traversal).
299 void initialize();
301 Reference<XInputStream> getStream(const OUString& rPath);
302 Reference<XInputStream> const& getStream(std::size_t nId);
304 private:
305 void traverse(const Reference<container::XNameAccess>& rxEnum);
307 Reference<XInputStream> createStream(const OUString& rPath);
309 public:
310 Reference<container::XNameAccess> mxContainer; //< root of the Zip
311 ::std::vector<ZipStreamData> maStreams; //< list of streams and their names
312 NameMap_t maNameMap; //< map of stream names to indexes (into @c maStreams)
313 bool mbInitialized;
316 ZipStreamData::ZipStreamData(const OString& rName)
317 : xStream()
318 , aName(rName)
322 ZipStorageImpl::ZipStorageImpl(const Reference<container::XNameAccess>& rxContainer)
323 : mxContainer(rxContainer)
324 , maStreams()
325 , maNameMap()
326 , mbInitialized(false)
328 assert(mxContainer.is());
331 void ZipStorageImpl::initialize()
333 traverse(mxContainer);
335 mbInitialized = true;
338 Reference<XInputStream> ZipStorageImpl::getStream(const OUString& rPath)
340 const OUString aPath(lcl_normalizeSubStreamPath(rPath));
341 NameMap_t::iterator aIt = maNameMap.find(aPath);
343 // For the while don't return stream in this situation.
344 // Later, given how libcdr's zip stream implementation behaves,
345 // return the first stream in the storage if there is one.
346 if (maNameMap.end() == aIt)
347 return Reference<XInputStream>();
349 if (!maStreams[aIt->second].xStream.is())
350 maStreams[aIt->second].xStream = createStream(aPath);
352 return maStreams[aIt->second].xStream;
355 Reference<XInputStream> const& ZipStorageImpl::getStream(const std::size_t nId)
357 if (!maStreams[nId].xStream.is())
358 maStreams[nId].xStream
359 = createStream(OStringToOUString(maStreams[nId].aName, RTL_TEXTENCODING_UTF8));
361 return maStreams[nId].xStream;
364 void ZipStorageImpl::traverse(const Reference<container::XNameAccess>& rxContainer)
366 const Sequence<OUString> lNames = rxContainer->getElementNames();
368 maStreams.reserve(lNames.getLength());
370 for (const auto& rName : lNames)
372 if (!rName.endsWith("/")) // skip dirs
374 maStreams.emplace_back(OUStringToOString(rName, RTL_TEXTENCODING_UTF8));
375 maNameMap[rName] = maStreams.size() - 1;
380 Reference<XInputStream> ZipStorageImpl::createStream(const OUString& rPath)
382 Reference<XInputStream> xStream;
386 const Reference<XInputStream> xInputStream(mxContainer->getByName(rPath), UNO_QUERY_THROW);
387 const Reference<XSeekable> xSeekable(xInputStream, UNO_QUERY);
389 if (xSeekable.is())
390 xStream = xInputStream;
391 else
392 xStream.set(new comphelper::OSeekableInputWrapper(
393 xInputStream, comphelper::getProcessComponentContext()));
395 catch (const Exception&)
397 // nothing needed
400 return xStream;
404 class WPXSvInputStreamImpl
406 public:
407 explicit WPXSvInputStreamImpl(css::uno::Reference<css::io::XInputStream> const& xStream);
409 bool isStructured();
410 unsigned subStreamCount();
411 const char* subStreamName(unsigned id);
412 bool existsSubStream(const char* name);
413 librevenge::RVNGInputStream* getSubStreamByName(const char* name);
414 librevenge::RVNGInputStream* getSubStreamById(unsigned id);
416 const unsigned char* read(unsigned long numBytes, unsigned long& numBytesRead);
417 int seek(long offset);
418 long tell();
419 bool isEnd();
421 void invalidateReadBuffer();
423 private:
424 bool isOLE();
425 void ensureOLEIsInitialized();
427 bool isZip();
428 void ensureZipIsInitialized();
430 static librevenge::RVNGInputStream*
431 createWPXStream(const tools::SvRef<SotStorageStream>& rxStorage);
432 static librevenge::RVNGInputStream* createWPXStream(const Reference<XInputStream>& rxStream);
434 private:
435 css::uno::Reference<css::io::XInputStream> mxStream;
436 css::uno::Reference<css::io::XSeekable> mxSeekable;
437 css::uno::Sequence<sal_Int8> maData;
438 std::unique_ptr<OLEStorageImpl> mpOLEStorage;
439 std::unique_ptr<ZipStorageImpl> mpZipStorage;
440 bool mbCheckedOLE;
441 bool mbCheckedZip;
443 public:
444 sal_Int64 mnLength;
445 const unsigned char* mpReadBuffer;
446 unsigned long mnReadBufferLength;
447 unsigned long mnReadBufferPos;
450 WPXSvInputStreamImpl::WPXSvInputStreamImpl(Reference<XInputStream> const& xStream)
451 : mxStream(xStream)
452 , mxSeekable(xStream, UNO_QUERY)
453 , maData(0)
454 , mbCheckedOLE(false)
455 , mbCheckedZip(false)
456 , mnLength(0)
457 , mpReadBuffer(nullptr)
458 , mnReadBufferLength(0)
459 , mnReadBufferPos(0)
461 if (!xStream.is() || !mxStream.is())
462 mnLength = 0;
463 else
465 if (!mxSeekable.is())
466 mnLength = 0;
467 else
471 mnLength = mxSeekable->getLength();
472 if (0 < mxSeekable->getPosition())
473 mxSeekable->seek(0);
475 catch (...)
477 SAL_WARN("writerperfect", "mnLength = mxSeekable->getLength() threw exception");
478 mnLength = 0;
484 const unsigned char* WPXSvInputStreamImpl::read(unsigned long numBytes, unsigned long& numBytesRead)
486 numBytesRead = 0;
488 if (numBytes == 0 || isEnd())
489 return nullptr;
491 numBytesRead = mxStream->readSomeBytes(maData, numBytes);
492 if (numBytesRead == 0)
493 return nullptr;
495 return reinterpret_cast<const unsigned char*>(maData.getConstArray());
498 long WPXSvInputStreamImpl::tell()
500 if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
501 return -1;
502 else
504 const sal_Int64 tmpPosition = mxSeekable->getPosition();
505 if ((tmpPosition < 0) || (tmpPosition > LONG_MAX))
506 return -1;
507 return static_cast<long>(tmpPosition);
511 int WPXSvInputStreamImpl::seek(long offset)
513 if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
514 return -1;
516 const sal_Int64 tmpPosition = mxSeekable->getPosition();
517 if ((tmpPosition < 0) || (tmpPosition > LONG_MAX))
518 return -1;
522 mxSeekable->seek(offset);
523 return 0;
525 catch (...)
527 SAL_WARN("writerperfect", "mxSeekable->seek(offset) threw exception");
528 return -1;
532 bool WPXSvInputStreamImpl::isEnd()
534 if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
535 return true;
536 return (mxSeekable->getPosition() >= mnLength);
539 bool WPXSvInputStreamImpl::isStructured()
541 if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
542 return false;
544 PositionHolder pos(mxSeekable);
545 mxSeekable->seek(0);
547 if (isOLE())
548 return true;
550 mxSeekable->seek(0);
552 return isZip();
555 unsigned WPXSvInputStreamImpl::subStreamCount()
557 if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
558 return 0;
560 PositionHolder pos(mxSeekable);
561 mxSeekable->seek(0);
563 if (isOLE())
565 ensureOLEIsInitialized();
567 return mpOLEStorage->maStreams.size();
570 mxSeekable->seek(0);
572 if (isZip())
574 ensureZipIsInitialized();
576 return mpZipStorage->maStreams.size();
579 return 0;
582 const char* WPXSvInputStreamImpl::subStreamName(const unsigned id)
584 if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
585 return nullptr;
587 PositionHolder pos(mxSeekable);
588 mxSeekable->seek(0);
590 if (isOLE())
592 ensureOLEIsInitialized();
594 if (mpOLEStorage->maStreams.size() <= id)
595 return nullptr;
597 return mpOLEStorage->maStreams[id].RVNGname.getStr();
600 mxSeekable->seek(0);
602 if (isZip())
604 ensureZipIsInitialized();
606 if (mpZipStorage->maStreams.size() <= id)
607 return nullptr;
609 return mpZipStorage->maStreams[id].aName.getStr();
612 return nullptr;
615 bool WPXSvInputStreamImpl::existsSubStream(const char* const name)
617 if (!name)
618 return false;
620 if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
621 return false;
623 PositionHolder pos(mxSeekable);
624 mxSeekable->seek(0);
626 const OUString aName(OStringToOUString(OString(name), RTL_TEXTENCODING_UTF8));
628 if (isOLE())
630 ensureOLEIsInitialized();
631 return mpOLEStorage->maNameMap.end() != mpOLEStorage->maNameMap.find(aName);
634 mxSeekable->seek(0);
636 if (isZip())
638 ensureZipIsInitialized();
639 return mpZipStorage->maNameMap.end() != mpZipStorage->maNameMap.find(aName);
642 return false;
645 librevenge::RVNGInputStream* WPXSvInputStreamImpl::getSubStreamByName(const char* const name)
647 if (!name)
648 return nullptr;
650 if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
651 return nullptr;
653 PositionHolder pos(mxSeekable);
654 mxSeekable->seek(0);
656 const OUString aName(OStringToOUString(OString(name), RTL_TEXTENCODING_UTF8));
658 if (isOLE())
660 ensureOLEIsInitialized();
661 return createWPXStream(mpOLEStorage->getStream(aName));
664 mxSeekable->seek(0);
666 if (isZip())
668 ensureZipIsInitialized();
672 return createWPXStream(mpZipStorage->getStream(aName));
674 catch (const Exception&)
676 // nothing needed
680 return nullptr;
683 librevenge::RVNGInputStream* WPXSvInputStreamImpl::getSubStreamById(const unsigned id)
685 if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
686 return nullptr;
688 PositionHolder pos(mxSeekable);
689 mxSeekable->seek(0);
691 if (isOLE())
693 ensureOLEIsInitialized();
695 if (mpOLEStorage->maStreams.size() <= id)
696 return nullptr;
698 return createWPXStream(mpOLEStorage->getStream(id));
701 mxSeekable->seek(0);
703 if (isZip())
705 ensureZipIsInitialized();
707 if (mpZipStorage->maStreams.size() <= id)
708 return nullptr;
712 return createWPXStream(mpZipStorage->getStream(id));
714 catch (const Exception&)
716 // nothing needed
719 return nullptr;
722 void WPXSvInputStreamImpl::invalidateReadBuffer()
724 if (mpReadBuffer)
726 seek(tell() + static_cast<long>(mnReadBufferPos) - static_cast<long>(mnReadBufferLength));
727 mpReadBuffer = nullptr;
728 mnReadBufferPos = 0;
729 mnReadBufferLength = 0;
733 librevenge::RVNGInputStream*
734 WPXSvInputStreamImpl::createWPXStream(const tools::SvRef<SotStorageStream>& rxStorage)
736 if (rxStorage.is())
738 Reference<XInputStream> xContents(new utl::OSeekableInputStreamWrapper(rxStorage.get()));
739 return new WPXSvInputStream(xContents);
741 return nullptr;
744 librevenge::RVNGInputStream*
745 WPXSvInputStreamImpl::createWPXStream(const Reference<XInputStream>& rxStream)
747 if (rxStream.is())
748 return new WPXSvInputStream(rxStream);
749 else
750 return nullptr;
753 bool WPXSvInputStreamImpl::isOLE()
755 if (!mbCheckedOLE)
757 assert(0 == mxSeekable->getPosition());
759 std::unique_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(),
781 UNO_SET_THROW);
782 const Reference<packages::zip::XZipFileAccess2> xZip(
783 xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
784 "com.sun.star.packages.zip.ZipFileAccess", aArgs, xContext),
785 UNO_QUERY_THROW);
786 mpZipStorage.reset(new ZipStorageImpl(xZip));
788 catch (const Exception&)
790 // ignore
793 mbCheckedZip = true;
796 return bool(mpZipStorage);
799 void WPXSvInputStreamImpl::ensureOLEIsInitialized()
801 assert(mpOLEStorage);
803 if (!mpOLEStorage->mbInitialized)
804 mpOLEStorage->initialize(utl::UcbStreamHelper::CreateStream(mxStream));
807 void WPXSvInputStreamImpl::ensureZipIsInitialized()
809 assert(mpZipStorage);
811 if (!mpZipStorage->mbInitialized)
812 mpZipStorage->initialize();
815 WPXSvInputStream::WPXSvInputStream(Reference<XInputStream> const& xStream)
816 : mpImpl(new WPXSvInputStreamImpl(xStream))
820 WPXSvInputStream::~WPXSvInputStream() {}
822 #define BUFFER_MAX 65536
824 const unsigned char* WPXSvInputStream::read(unsigned long numBytes, unsigned long& numBytesRead)
826 numBytesRead = 0;
828 if (numBytes == 0 || numBytes > std::numeric_limits<unsigned long>::max() / 2)
829 return nullptr;
831 if (mpImpl->mpReadBuffer)
833 if ((mpImpl->mnReadBufferPos + numBytes > mpImpl->mnReadBufferPos)
834 && (mpImpl->mnReadBufferPos + numBytes <= mpImpl->mnReadBufferLength))
836 const unsigned char* pTmp = mpImpl->mpReadBuffer + mpImpl->mnReadBufferPos;
837 mpImpl->mnReadBufferPos += numBytes;
838 numBytesRead = numBytes;
839 return pTmp;
842 mpImpl->invalidateReadBuffer();
845 unsigned long curpos = static_cast<unsigned long>(mpImpl->tell());
846 if (curpos == static_cast<unsigned long>(-1)) // returned ERROR
847 return nullptr;
849 if ((curpos + numBytes < curpos) /*overflow*/
850 || (curpos + numBytes
851 >= static_cast<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 nullptr;
875 if (numBytes <= mpImpl->mnReadBufferLength)
876 numBytesRead = numBytes;
877 else
878 numBytesRead = mpImpl->mnReadBufferLength;
880 mpImpl->mnReadBufferPos += numBytesRead;
881 return mpImpl->mpReadBuffer;
884 long WPXSvInputStream::tell()
886 long retVal = mpImpl->tell();
887 return retVal - static_cast<long>(mpImpl->mnReadBufferLength)
888 + static_cast<long>(mpImpl->mnReadBufferPos);
891 int WPXSvInputStream::seek(long offset, librevenge::RVNG_SEEK_TYPE seekType)
893 sal_Int64 tmpOffset = offset;
894 if (seekType == librevenge::RVNG_SEEK_CUR)
895 tmpOffset += tell();
896 if (seekType == librevenge::RVNG_SEEK_END)
897 tmpOffset += mpImpl->mnLength;
899 int retVal = 0;
900 if (tmpOffset < 0)
902 tmpOffset = 0;
903 retVal = -1;
905 if (tmpOffset > mpImpl->mnLength)
907 tmpOffset = mpImpl->mnLength;
908 retVal = -1;
911 if (tmpOffset < mpImpl->tell()
912 && static_cast<unsigned long>(tmpOffset)
913 >= static_cast<unsigned long>(mpImpl->tell()) - mpImpl->mnReadBufferLength)
915 mpImpl->mnReadBufferPos = static_cast<unsigned long>(
916 tmpOffset + static_cast<long>(mpImpl->mnReadBufferLength) - mpImpl->tell());
917 return retVal;
920 mpImpl->invalidateReadBuffer();
922 if (mpImpl->seek(tmpOffset))
923 return -1;
924 return retVal;
927 bool WPXSvInputStream::isEnd()
929 return mpImpl->isEnd() && mpImpl->mnReadBufferPos == mpImpl->mnReadBufferLength;
932 bool WPXSvInputStream::isStructured()
934 mpImpl->invalidateReadBuffer();
935 return mpImpl->isStructured();
938 unsigned WPXSvInputStream::subStreamCount()
940 mpImpl->invalidateReadBuffer();
941 return mpImpl->subStreamCount();
944 const char* WPXSvInputStream::subStreamName(const unsigned id)
946 mpImpl->invalidateReadBuffer();
947 return mpImpl->subStreamName(id);
950 bool WPXSvInputStream::existsSubStream(const char* const name)
952 mpImpl->invalidateReadBuffer();
953 return mpImpl->existsSubStream(name);
956 librevenge::RVNGInputStream* WPXSvInputStream::getSubStreamByName(const char* name)
958 mpImpl->invalidateReadBuffer();
959 return mpImpl->getSubStreamByName(name);
962 librevenge::RVNGInputStream* WPXSvInputStream::getSubStreamById(const unsigned id)
964 mpImpl->invalidateReadBuffer();
965 return mpImpl->getSubStreamById(id);
969 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */