Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / writerperfect / source / common / WPXSvInputStream.cxx
blob45625927e3a121e326f3c4425ebc980092a75803
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>
17 #include <o3tl/safeint.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 <string_view>
31 #include <unordered_map>
32 #include <utility>
33 #include <vector>
35 namespace writerperfect
37 using namespace ::com::sun::star::uno;
38 using namespace ::com::sun::star::io;
40 namespace container = com::sun::star::container;
41 namespace packages = com::sun::star::packages;
43 namespace
45 class PositionHolder
47 public:
48 explicit PositionHolder(const Reference<XSeekable>& rxSeekable);
49 ~PositionHolder();
50 PositionHolder(const PositionHolder&) = delete;
51 PositionHolder& operator=(const PositionHolder&) = delete;
53 private:
54 const Reference<XSeekable> mxSeekable;
55 const sal_uInt64 mnPosition;
58 PositionHolder::PositionHolder(const Reference<XSeekable>& rxSeekable)
59 : mxSeekable(rxSeekable)
60 , mnPosition(rxSeekable->getPosition())
64 PositionHolder::~PositionHolder()
66 try
68 mxSeekable->seek(mnPosition);
70 catch (...)
75 } // anonymous namespace
77 namespace
79 OUString lcl_normalizeSubStreamPath(const OUString& rPath)
81 // accept paths which begin by '/'
82 // TODO: maybe this should do a full normalization
83 if (rPath.startsWith("/") && rPath.getLength() >= 2)
84 return rPath.copy(1);
85 return rPath;
89 namespace
91 OUString concatPath(std::u16string_view lhs, const OUString& rhs)
93 if (lhs.empty())
94 return rhs;
95 return OUString::Concat(lhs) + "/" + rhs;
98 struct OLEStreamData
100 OLEStreamData(OString aName, OString rvngName);
102 tools::SvRef<SotStorageStream> stream;
104 /** Name of the stream.
106 * This is not @c OUString, because we need to be able to
107 * produce const char* from it.
109 OString name;
110 /** librevenge name of the stream.
112 * This is not @c OUString, because we need to be able to
113 * produce const char* from it.
115 OString RVNGname;
118 typedef std::unordered_map<OUString, std::size_t> NameMap_t;
119 typedef std::unordered_map<OUString, tools::SvRef<SotStorage>> OLEStorageMap_t;
121 /** Representation of an OLE2 storage.
123 * This class tries to bring a bit of sanity to use of SotStorage with
124 * respect to the needs of @c librevenge::RVNGInputStream API. It
125 * holds all nested storages for the whole lifetime (more precisely,
126 * since initialization, which is performed by calling @c
127 * initialize()), thus ensuring that no created stream is destroyed
128 * just because its parent storage went out of scope. It also holds a
129 * bidirectional map of stream names to their indexes (index of a
130 * stream is determined by deep-first traversal), which is also
131 * populated during initialization (member variables @c maStreams and
132 * @c maNameMap).
134 * Streams are created on demand (and saved, for the same reason as
135 * storages).
137 struct OLEStorageImpl
139 OLEStorageImpl();
141 void initialize(std::unique_ptr<SvStream> pStream);
143 tools::SvRef<SotStorageStream> getStream(const OUString& rPath);
144 tools::SvRef<SotStorageStream> const& getStream(std::size_t nId);
146 private:
147 void traverse(const tools::SvRef<SotStorage>& rStorage, std::u16string_view rPath);
149 tools::SvRef<SotStorageStream> createStream(const OUString& rPath);
151 public:
152 tools::SvRef<SotStorage> mxRootStorage; //< root storage of the OLE2
153 OLEStorageMap_t maStorageMap; //< map of all sub storages by name
154 ::std::vector<OLEStreamData> maStreams; //< list of streams and their names
155 NameMap_t maNameMap; //< map of stream names to indexes (into @c maStreams)
156 bool mbInitialized;
159 OLEStreamData::OLEStreamData(OString aName, OString rvngName)
160 : name(std::move(aName))
161 , RVNGname(std::move(rvngName))
165 OLEStorageImpl::OLEStorageImpl()
166 : mbInitialized(false)
170 void OLEStorageImpl::initialize(std::unique_ptr<SvStream> pStream)
172 if (!pStream)
173 return;
175 mxRootStorage = new SotStorage(pStream.release(), true);
177 traverse(mxRootStorage, u"");
179 mbInitialized = true;
182 tools::SvRef<SotStorageStream> OLEStorageImpl::getStream(const OUString& rPath)
184 const OUString aPath(lcl_normalizeSubStreamPath(rPath));
185 NameMap_t::iterator aIt = maNameMap.find(aPath);
187 // For the while don't return stream in this situation.
188 // Later, given how libcdr's zip stream implementation behaves,
189 // return the first stream in the storage if there is one.
190 if (maNameMap.end() == aIt)
191 return tools::SvRef<SotStorageStream>();
193 if (!maStreams[aIt->second].stream.is())
194 maStreams[aIt->second].stream
195 = createStream(OStringToOUString(maStreams[aIt->second].name, RTL_TEXTENCODING_UTF8));
197 return maStreams[aIt->second].stream;
200 tools::SvRef<SotStorageStream> const& OLEStorageImpl::getStream(const std::size_t nId)
202 if (!maStreams[nId].stream.is())
203 maStreams[nId].stream
204 = createStream(OStringToOUString(maStreams[nId].name, RTL_TEXTENCODING_UTF8));
206 return maStreams[nId].stream;
209 void OLEStorageImpl::traverse(const tools::SvRef<SotStorage>& rStorage, std::u16string_view rPath)
211 SvStorageInfoList infos;
213 rStorage->FillInfoList(&infos);
215 for (const auto& info : infos)
217 if (info.IsStream())
219 OUString baseName = info.GetName(), rvngName = baseName;
220 // librevenge::RVNGOLEStream ignores the first character when is a control code, so ...
221 if (!rvngName.isEmpty() && rvngName.toChar() < 32)
222 rvngName = rvngName.copy(1);
223 maStreams.emplace_back(
224 OUStringToOString(concatPath(rPath, baseName), RTL_TEXTENCODING_UTF8),
225 OUStringToOString(concatPath(rPath, rvngName), RTL_TEXTENCODING_UTF8));
226 maNameMap[concatPath(rPath, rvngName)] = maStreams.size() - 1;
228 else if (info.IsStorage())
230 const OUString aPath = concatPath(rPath, info.GetName());
231 tools::SvRef<SotStorage> aStorage
232 = rStorage->OpenSotStorage(info.GetName(), StreamMode::STD_READ);
233 maStorageMap[aPath] = aStorage;
235 // deep-first traversal
236 traverse(aStorage, aPath);
238 else
240 SAL_WARN("writerperfect",
241 "OLEStorageImpl::traverse: invalid storage entry, neither stream nor file");
246 tools::SvRef<SotStorageStream> OLEStorageImpl::createStream(const OUString& rPath)
248 const sal_Int32 nDelim = rPath.lastIndexOf(u'/');
250 if (-1 == nDelim)
251 return mxRootStorage->OpenSotStream(rPath, StreamMode::STD_READ);
253 const OUString aDir = rPath.copy(0, nDelim);
254 const OUString aName = rPath.copy(nDelim + 1);
256 const OLEStorageMap_t::const_iterator aIt = maStorageMap.find(aDir);
258 if (maStorageMap.end() == aIt)
259 return nullptr;
261 return aIt->second->OpenSotStream(aName, StreamMode::STD_READ);
265 namespace
267 struct ZipStreamData
269 explicit ZipStreamData(OString aName);
271 Reference<XInputStream> xStream;
273 /** Name of the stream.
275 * This is not @c OUString, because we need to be able to
276 * produce const char* from it.
278 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 explicit 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 OUString& rPath);
299 Reference<XInputStream> const& getStream(std::size_t nId);
301 private:
302 void traverse(const Reference<container::XNameAccess>& rxEnum);
304 Reference<XInputStream> createStream(const 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(OString _aName)
314 : aName(std::move(_aName))
318 ZipStorageImpl::ZipStorageImpl(const Reference<container::XNameAccess>& rxContainer)
319 : mxContainer(rxContainer)
320 , mbInitialized(false)
322 assert(mxContainer.is());
325 void ZipStorageImpl::initialize()
327 traverse(mxContainer);
329 mbInitialized = true;
332 Reference<XInputStream> ZipStorageImpl::getStream(const OUString& rPath)
334 const OUString aPath(lcl_normalizeSubStreamPath(rPath));
335 NameMap_t::iterator aIt = maNameMap.find(aPath);
337 // For the while don't return stream in this situation.
338 // Later, given how libcdr's zip stream implementation behaves,
339 // return the first stream in the storage if there is one.
340 if (maNameMap.end() == aIt)
341 return Reference<XInputStream>();
343 if (!maStreams[aIt->second].xStream.is())
344 maStreams[aIt->second].xStream = createStream(aPath);
346 return maStreams[aIt->second].xStream;
349 Reference<XInputStream> const& ZipStorageImpl::getStream(const std::size_t nId)
351 if (!maStreams[nId].xStream.is())
352 maStreams[nId].xStream
353 = createStream(OStringToOUString(maStreams[nId].aName, RTL_TEXTENCODING_UTF8));
355 return maStreams[nId].xStream;
358 void ZipStorageImpl::traverse(const Reference<container::XNameAccess>& rxContainer)
360 const Sequence<OUString> lNames = rxContainer->getElementNames();
362 maStreams.reserve(lNames.getLength());
364 for (const auto& rName : lNames)
366 if (!rName.endsWith("/")) // skip dirs
368 maStreams.emplace_back(OUStringToOString(rName, RTL_TEXTENCODING_UTF8));
369 maNameMap[rName] = maStreams.size() - 1;
374 Reference<XInputStream> ZipStorageImpl::createStream(const OUString& rPath)
376 Reference<XInputStream> xStream;
380 const Reference<XInputStream> xInputStream(mxContainer->getByName(rPath), UNO_QUERY_THROW);
381 const Reference<XSeekable> xSeekable(xInputStream, UNO_QUERY);
383 if (xSeekable.is())
384 xStream = xInputStream;
385 else
386 xStream.set(new comphelper::OSeekableInputWrapper(
387 xInputStream, comphelper::getProcessComponentContext()));
389 catch (const Exception&)
391 // nothing needed
394 return xStream;
398 class WPXSvInputStreamImpl
400 public:
401 explicit WPXSvInputStreamImpl(css::uno::Reference<css::io::XInputStream> const& xStream);
403 bool isStructured();
404 unsigned subStreamCount();
405 const char* subStreamName(unsigned id);
406 bool existsSubStream(const char* name);
407 librevenge::RVNGInputStream* getSubStreamByName(const char* name);
408 librevenge::RVNGInputStream* getSubStreamById(unsigned id);
410 const unsigned char* read(unsigned long numBytes, unsigned long& numBytesRead);
411 int seek(tools::Long offset);
412 tools::Long tell();
413 bool isEnd();
415 void invalidateReadBuffer();
417 private:
418 bool isOLE();
419 void ensureOLEIsInitialized();
421 bool isZip();
422 void ensureZipIsInitialized();
424 static librevenge::RVNGInputStream*
425 createWPXStream(const tools::SvRef<SotStorageStream>& rxStorage);
426 static librevenge::RVNGInputStream* createWPXStream(const Reference<XInputStream>& rxStream);
428 private:
429 css::uno::Reference<css::io::XInputStream> mxStream;
430 css::uno::Reference<css::io::XSeekable> mxSeekable;
431 css::uno::Sequence<sal_Int8> maData;
432 std::unique_ptr<OLEStorageImpl> mpOLEStorage;
433 std::unique_ptr<ZipStorageImpl> mpZipStorage;
434 bool mbCheckedOLE;
435 bool mbCheckedZip;
437 public:
438 sal_Int64 mnLength;
439 const unsigned char* mpReadBuffer;
440 unsigned long mnReadBufferLength;
441 unsigned long mnReadBufferPos;
444 WPXSvInputStreamImpl::WPXSvInputStreamImpl(Reference<XInputStream> const& xStream)
445 : mxStream(xStream)
446 , mxSeekable(xStream, UNO_QUERY)
447 , maData(0)
448 , mbCheckedOLE(false)
449 , mbCheckedZip(false)
450 , mnLength(0)
451 , mpReadBuffer(nullptr)
452 , mnReadBufferLength(0)
453 , mnReadBufferPos(0)
455 if (!xStream.is() || !mxStream.is())
456 mnLength = 0;
457 else
459 if (!mxSeekable.is())
460 mnLength = 0;
461 else
465 mnLength = mxSeekable->getLength();
466 if (0 < mxSeekable->getPosition())
467 mxSeekable->seek(0);
469 catch (...)
471 SAL_WARN("writerperfect", "mnLength = mxSeekable->getLength() threw exception");
472 mnLength = 0;
478 const unsigned char* WPXSvInputStreamImpl::read(unsigned long numBytes, unsigned long& numBytesRead)
480 numBytesRead = 0;
482 if (numBytes == 0 || isEnd())
483 return nullptr;
485 numBytesRead = mxStream->readSomeBytes(maData, numBytes);
486 if (numBytesRead == 0)
487 return nullptr;
489 return reinterpret_cast<const unsigned char*>(maData.getConstArray());
492 tools::Long WPXSvInputStreamImpl::tell()
494 if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
495 return -1;
496 else
498 const sal_Int64 tmpPosition = mxSeekable->getPosition();
499 if ((tmpPosition < 0) || (tmpPosition > LONG_MAX))
500 return -1;
501 return static_cast<tools::Long>(tmpPosition);
505 int WPXSvInputStreamImpl::seek(tools::Long offset)
507 if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
508 return -1;
510 const sal_Int64 tmpPosition = mxSeekable->getPosition();
511 if ((tmpPosition < 0) || (tmpPosition > LONG_MAX))
512 return -1;
516 mxSeekable->seek(offset);
517 return 0;
519 catch (...)
521 SAL_WARN("writerperfect", "mxSeekable->seek(offset) threw exception");
522 return -1;
526 bool WPXSvInputStreamImpl::isEnd()
528 if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
529 return true;
530 return (mxSeekable->getPosition() >= mnLength);
533 bool WPXSvInputStreamImpl::isStructured()
535 if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
536 return false;
538 PositionHolder pos(mxSeekable);
539 mxSeekable->seek(0);
541 if (isOLE())
542 return true;
544 mxSeekable->seek(0);
546 return isZip();
549 unsigned WPXSvInputStreamImpl::subStreamCount()
551 if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
552 return 0;
554 PositionHolder pos(mxSeekable);
555 mxSeekable->seek(0);
557 if (isOLE())
559 ensureOLEIsInitialized();
561 return mpOLEStorage->maStreams.size();
564 mxSeekable->seek(0);
566 if (isZip())
568 ensureZipIsInitialized();
570 return mpZipStorage->maStreams.size();
573 return 0;
576 const char* WPXSvInputStreamImpl::subStreamName(const unsigned id)
578 if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
579 return nullptr;
581 PositionHolder pos(mxSeekable);
582 mxSeekable->seek(0);
584 if (isOLE())
586 ensureOLEIsInitialized();
588 if (mpOLEStorage->maStreams.size() <= id)
589 return nullptr;
591 return mpOLEStorage->maStreams[id].RVNGname.getStr();
594 mxSeekable->seek(0);
596 if (isZip())
598 ensureZipIsInitialized();
600 if (mpZipStorage->maStreams.size() <= id)
601 return nullptr;
603 return mpZipStorage->maStreams[id].aName.getStr();
606 return nullptr;
609 bool WPXSvInputStreamImpl::existsSubStream(const char* const name)
611 if (!name)
612 return false;
614 if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
615 return false;
617 PositionHolder pos(mxSeekable);
618 mxSeekable->seek(0);
620 const OUString aName(OStringToOUString(std::string_view(name), RTL_TEXTENCODING_UTF8));
622 if (isOLE())
624 ensureOLEIsInitialized();
625 return mpOLEStorage->maNameMap.end() != mpOLEStorage->maNameMap.find(aName);
628 mxSeekable->seek(0);
630 if (isZip())
632 ensureZipIsInitialized();
633 return mpZipStorage->maNameMap.end() != mpZipStorage->maNameMap.find(aName);
636 return false;
639 librevenge::RVNGInputStream* WPXSvInputStreamImpl::getSubStreamByName(const char* const name)
641 if (!name)
642 return nullptr;
644 if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
645 return nullptr;
647 PositionHolder pos(mxSeekable);
648 mxSeekable->seek(0);
650 const OUString aName(OStringToOUString(std::string_view(name), RTL_TEXTENCODING_UTF8));
652 if (isOLE())
654 ensureOLEIsInitialized();
655 return createWPXStream(mpOLEStorage->getStream(aName));
658 mxSeekable->seek(0);
660 if (isZip())
662 ensureZipIsInitialized();
666 return createWPXStream(mpZipStorage->getStream(aName));
668 catch (const Exception&)
670 // nothing needed
674 return nullptr;
677 librevenge::RVNGInputStream* WPXSvInputStreamImpl::getSubStreamById(const unsigned id)
679 if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
680 return nullptr;
682 PositionHolder pos(mxSeekable);
683 mxSeekable->seek(0);
685 if (isOLE())
687 ensureOLEIsInitialized();
689 if (mpOLEStorage->maStreams.size() <= id)
690 return nullptr;
692 return createWPXStream(mpOLEStorage->getStream(id));
695 mxSeekable->seek(0);
697 if (isZip())
699 ensureZipIsInitialized();
701 if (mpZipStorage->maStreams.size() <= id)
702 return nullptr;
706 return createWPXStream(mpZipStorage->getStream(id));
708 catch (const Exception&)
710 // nothing needed
713 return nullptr;
716 void WPXSvInputStreamImpl::invalidateReadBuffer()
718 if (mpReadBuffer)
720 seek(tell() + static_cast<tools::Long>(mnReadBufferPos)
721 - static_cast<tools::Long>(mnReadBufferLength));
722 mpReadBuffer = nullptr;
723 mnReadBufferPos = 0;
724 mnReadBufferLength = 0;
728 librevenge::RVNGInputStream*
729 WPXSvInputStreamImpl::createWPXStream(const tools::SvRef<SotStorageStream>& rxStorage)
731 if (rxStorage.is())
733 Reference<XInputStream> xContents(new utl::OSeekableInputStreamWrapper(rxStorage.get()));
734 return new WPXSvInputStream(xContents);
736 return nullptr;
739 librevenge::RVNGInputStream*
740 WPXSvInputStreamImpl::createWPXStream(const Reference<XInputStream>& rxStream)
742 if (rxStream.is())
743 return new WPXSvInputStream(rxStream);
744 else
745 return nullptr;
748 bool WPXSvInputStreamImpl::isOLE()
750 if (!mbCheckedOLE)
752 assert(0 == mxSeekable->getPosition());
754 std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(mxStream));
755 if (pStream && SotStorage::IsOLEStorage(pStream.get()))
756 mpOLEStorage.reset(new OLEStorageImpl());
758 mbCheckedOLE = true;
761 return bool(mpOLEStorage);
764 bool WPXSvInputStreamImpl::isZip()
766 if (!mbCheckedZip)
768 assert(0 == mxSeekable->getPosition());
772 const Reference<XComponentContext> xContext(comphelper::getProcessComponentContext(),
773 UNO_SET_THROW);
774 const Reference<packages::zip::XZipFileAccess2> xZip(
775 xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
776 "com.sun.star.packages.zip.ZipFileAccess", { Any(mxStream) }, xContext),
777 UNO_QUERY_THROW);
778 mpZipStorage.reset(new ZipStorageImpl(xZip));
780 catch (const Exception&)
782 // ignore
785 mbCheckedZip = true;
788 return bool(mpZipStorage);
791 void WPXSvInputStreamImpl::ensureOLEIsInitialized()
793 assert(mpOLEStorage);
795 if (!mpOLEStorage->mbInitialized)
796 mpOLEStorage->initialize(utl::UcbStreamHelper::CreateStream(mxStream));
799 void WPXSvInputStreamImpl::ensureZipIsInitialized()
801 assert(mpZipStorage);
803 if (!mpZipStorage->mbInitialized)
804 mpZipStorage->initialize();
807 WPXSvInputStream::WPXSvInputStream(Reference<XInputStream> const& xStream)
808 : mpImpl(new WPXSvInputStreamImpl(xStream))
812 WPXSvInputStream::~WPXSvInputStream() {}
814 #define BUFFER_MAX 65536
816 const unsigned char* WPXSvInputStream::read(unsigned long numBytes, unsigned long& numBytesRead)
818 numBytesRead = 0;
820 if (numBytes == 0 || numBytes > std::numeric_limits<unsigned long>::max() / 2)
821 return nullptr;
823 if (mpImpl->mpReadBuffer)
825 if ((mpImpl->mnReadBufferPos + numBytes > mpImpl->mnReadBufferPos)
826 && (mpImpl->mnReadBufferPos + numBytes <= mpImpl->mnReadBufferLength))
828 const unsigned char* pTmp = mpImpl->mpReadBuffer + mpImpl->mnReadBufferPos;
829 mpImpl->mnReadBufferPos += numBytes;
830 numBytesRead = numBytes;
831 return pTmp;
834 mpImpl->invalidateReadBuffer();
837 unsigned long curpos = static_cast<unsigned long>(mpImpl->tell());
838 if (curpos == static_cast<unsigned long>(-1)) // returned ERROR
839 return nullptr;
841 if ((curpos + numBytes < curpos) /*overflow*/
842 || (curpos + numBytes
843 >= o3tl::make_unsigned(mpImpl->mnLength))) /*reading more than available*/
845 numBytes = mpImpl->mnLength - curpos;
848 if (numBytes < BUFFER_MAX)
850 if (BUFFER_MAX < mpImpl->mnLength - curpos)
851 mpImpl->mnReadBufferLength = BUFFER_MAX;
852 else /* BUFFER_MAX >= mpImpl->mnLength - curpos */
853 mpImpl->mnReadBufferLength = mpImpl->mnLength - curpos;
855 else
856 mpImpl->mnReadBufferLength = numBytes;
858 unsigned long tmpNumBytes(0);
859 mpImpl->mpReadBuffer = mpImpl->read(mpImpl->mnReadBufferLength, tmpNumBytes);
860 if (tmpNumBytes != mpImpl->mnReadBufferLength)
861 mpImpl->mnReadBufferLength = tmpNumBytes;
863 mpImpl->mnReadBufferPos = 0;
864 if (!mpImpl->mnReadBufferLength)
865 return nullptr;
867 if (numBytes <= mpImpl->mnReadBufferLength)
868 numBytesRead = numBytes;
869 else
870 numBytesRead = mpImpl->mnReadBufferLength;
872 mpImpl->mnReadBufferPos += numBytesRead;
873 return mpImpl->mpReadBuffer;
876 long WPXSvInputStream::tell()
878 tools::Long retVal = mpImpl->tell();
879 return retVal - static_cast<tools::Long>(mpImpl->mnReadBufferLength)
880 + static_cast<tools::Long>(mpImpl->mnReadBufferPos);
883 int WPXSvInputStream::seek(long offset, librevenge::RVNG_SEEK_TYPE seekType)
885 sal_Int64 tmpOffset = offset;
886 if (seekType == librevenge::RVNG_SEEK_CUR)
887 tmpOffset += tell();
888 if (seekType == librevenge::RVNG_SEEK_END)
889 tmpOffset += mpImpl->mnLength;
891 int retVal = 0;
892 if (tmpOffset < 0)
894 tmpOffset = 0;
895 retVal = -1;
897 if (tmpOffset > mpImpl->mnLength)
899 tmpOffset = mpImpl->mnLength;
900 retVal = -1;
903 if (tmpOffset < mpImpl->tell()
904 && o3tl::make_unsigned(tmpOffset)
905 >= static_cast<unsigned long>(mpImpl->tell()) - mpImpl->mnReadBufferLength)
907 mpImpl->mnReadBufferPos = static_cast<unsigned long>(
908 tmpOffset + static_cast<tools::Long>(mpImpl->mnReadBufferLength) - mpImpl->tell());
909 return retVal;
912 mpImpl->invalidateReadBuffer();
914 if (mpImpl->seek(tmpOffset))
915 return -1;
916 return retVal;
919 bool WPXSvInputStream::isEnd()
921 return mpImpl->isEnd() && mpImpl->mnReadBufferPos == mpImpl->mnReadBufferLength;
924 bool WPXSvInputStream::isStructured()
926 mpImpl->invalidateReadBuffer();
927 return mpImpl->isStructured();
930 unsigned WPXSvInputStream::subStreamCount()
932 mpImpl->invalidateReadBuffer();
933 return mpImpl->subStreamCount();
936 const char* WPXSvInputStream::subStreamName(const unsigned id)
938 mpImpl->invalidateReadBuffer();
939 return mpImpl->subStreamName(id);
942 bool WPXSvInputStream::existsSubStream(const char* const name)
944 mpImpl->invalidateReadBuffer();
945 return mpImpl->existsSubStream(name);
948 librevenge::RVNGInputStream* WPXSvInputStream::getSubStreamByName(const char* name)
950 mpImpl->invalidateReadBuffer();
951 return mpImpl->getSubStreamByName(name);
954 librevenge::RVNGInputStream* WPXSvInputStream::getSubStreamById(const unsigned id)
956 mpImpl->invalidateReadBuffer();
957 return mpImpl->getSubStreamById(id);
961 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */