/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * */ #include #include #include #include #include #include struct BinaryDataContainer::Impl { // temp file to store the data out of RAM if necessary std::unique_ptr mpFile; // the binary data std::shared_ptr> mpData; Impl(SvStream& stream, size_t size) { readData(stream, size); } /// Populate mpData from the stream void readData(SvStream& stream, size_t size) { auto pData = std::make_shared>(size); if (stream.ReadBytes(pData->data(), pData->size()) == size) mpData = std::move(pData); } /// ensure the data is in-RAM void ensureSwappedIn() { if (mpData || !mpFile) return; auto pStream = mpFile->GetStream(StreamMode::READ); pStream->Seek(0); readData(*pStream, pStream->remainingSize()); // Horrifying data loss ... SAL_WARN_IF(pStream->GetError(), "vcl", "Inconsistent system - failed to swap image back in"); } void swapOut() { if (mpFile) { // we already have it swapped out. mpData.reset(); return; } if (!mpData || mpData->empty()) return; mpFile.reset(new utl::TempFileFast()); auto pStream = mpFile->GetStream(StreamMode::READWRITE); pStream->WriteBytes(mpData->data(), mpData->size()); mpData.reset(); } }; BinaryDataContainer::BinaryDataContainer(SvStream& stream, size_t size) : mpImpl(new Impl(stream, size)) { } size_t BinaryDataContainer::calculateHash() const { size_t nSeed = 0; if (mpImpl && mpImpl->mpData && !mpImpl->mpData->empty()) { o3tl::hash_combine(nSeed, getSize()); for (sal_uInt8 const& rByte : *mpImpl->mpData) o3tl::hash_combine(nSeed, rByte); } return nSeed; } css::uno::Sequence BinaryDataContainer::getCopyAsByteSequence() const { if (isEmpty()) return css::uno::Sequence(); assert(mpImpl); css::uno::Sequence aData(getSize()); std::copy(mpImpl->mpData->cbegin(), mpImpl->mpData->cend(), aData.getArray()); return aData; } namespace { /* * Hold a reference on the internal state in case we swap out * and free the vector while someone holds an SvStream pointer. */ class ReferencedMemoryStream : public SvMemoryStream { std::shared_ptr> mpData; public: ReferencedMemoryStream(const std::shared_ptr>& pData) : SvMemoryStream(pData->data(), pData->size(), StreamMode::READ) , mpData(pData) { } }; class ReferencedXInputStream : public comphelper::MemoryInputStream { std::shared_ptr> mpData; public: ReferencedXInputStream(const std::shared_ptr>& pData) : comphelper::MemoryInputStream(reinterpret_cast(pData->data()), pData->size()) , mpData(pData) { } }; } std::shared_ptr BinaryDataContainer::getAsStream() { ensureSwappedIn(); // TODO: transfer in streamed chunks return std::make_shared(mpImpl->mpData); } css::uno::Reference BinaryDataContainer::getAsXInputStream() { ensureSwappedIn(); // TODO: transfer in streamed chunks return new ReferencedXInputStream(mpImpl->mpData); } std::size_t BinaryDataContainer::writeToStream(SvStream& rStream) const { ensureSwappedIn(); // TODO: transfer in streamed chunks return rStream.WriteBytes(getData(), getSize()); } size_t BinaryDataContainer::getSize() const { ensureSwappedIn(); return mpImpl && mpImpl->mpData ? mpImpl->mpData->size() : 0; } size_t BinaryDataContainer::getSizeBytes() const { return mpImpl && mpImpl->mpData ? mpImpl->mpData->size() : 0; } bool BinaryDataContainer::isEmpty() const { ensureSwappedIn(); return !mpImpl || !mpImpl->mpData || mpImpl->mpData->empty(); } const sal_uInt8* BinaryDataContainer::getData() const { ensureSwappedIn(); return mpImpl && mpImpl->mpData ? mpImpl->mpData->data() : nullptr; } void BinaryDataContainer::ensureSwappedIn() const { if (mpImpl) mpImpl->ensureSwappedIn(); } void BinaryDataContainer::swapOut() const { // Only bother reducing memory footprint in kit mode - for mobile/online etc. if (!mpImpl || !comphelper::LibreOfficeKit::isActive()) return; mpImpl->swapOut(); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */