summaryrefslogtreecommitdiffstats
path: root/filter/source/xsltfilter/OleHandler.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'filter/source/xsltfilter/OleHandler.cxx')
-rw-r--r--filter/source/xsltfilter/OleHandler.cxx214
1 files changed, 214 insertions, 0 deletions
diff --git a/filter/source/xsltfilter/OleHandler.cxx b/filter/source/xsltfilter/OleHandler.cxx
new file mode 100644
index 000000000..bb2089935
--- /dev/null
+++ b/filter/source/xsltfilter/OleHandler.cxx
@@ -0,0 +1,214 @@
+/* -*- 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 <rtl/ustrbuf.hxx>
+
+#include <package/Inflater.hxx>
+#include <package/Deflater.hxx>
+
+#include <cppuhelper/factory.hxx>
+#include <comphelper/base64.hxx>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/io/TempFile.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/io/XSeekable.hpp>
+#include <com/sun/star/embed/XTransactedObject.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+
+#include "OleHandler.hxx"
+#include <optional>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::embed;
+
+
+namespace XSLT
+{
+ Reference<XStream> OleHandler::createTempFile() {
+ Reference<XStream> tempFile = TempFile::create(m_xContext);
+ OSL_ASSERT(tempFile.is());
+ return tempFile;
+ }
+
+ void OleHandler::ensureCreateRootStorage()
+ {
+ if (m_storage == nullptr || m_rootStream == nullptr)
+ {
+ m_rootStream = createTempFile();
+ Sequence<Any> args{ Any(m_rootStream->getInputStream()) };
+
+ Reference<XNameContainer> cont(
+ Reference<XMultiServiceFactory>(m_xContext->getServiceManager(), UNO_QUERY_THROW)
+ ->createInstanceWithArguments("com.sun.star.embed.OLESimpleStorage", args), UNO_QUERY);
+ m_storage = cont;
+ }
+ }
+
+ void OleHandler::initRootStorageFromBase64(std::string_view content)
+ {
+ Sequence<sal_Int8> oleData;
+ ::comphelper::Base64::decode(oleData, OStringToOUString(
+ content, RTL_TEXTENCODING_UTF8));
+ m_rootStream = createTempFile();
+ Reference<XOutputStream> xOutput = m_rootStream->getOutputStream();
+ xOutput->writeBytes(oleData);
+ xOutput->flush();
+ //Get the input stream and seek to begin
+ Reference<XSeekable> xSeek(m_rootStream->getInputStream(), UNO_QUERY);
+ xSeek->seek(0);
+
+ //create a com.sun.star.embed.OLESimpleStorage from the temp stream
+ Sequence<Any> args{ Any(xSeek) };
+ Reference<XNameContainer> cont(
+ Reference<XMultiServiceFactory>(m_xContext->getServiceManager(), UNO_QUERY_THROW)
+ ->createInstanceWithArguments("com.sun.star.embed.OLESimpleStorage", args), UNO_QUERY);
+ m_storage = cont;
+ }
+
+ OString
+ OleHandler::encodeSubStorage(const OUString& streamName)
+ {
+ if (!m_storage || !m_storage->hasByName(streamName))
+ {
+ return "Not Found:";// + streamName;
+ }
+
+ Reference<XInputStream> subStream(m_storage->getByName(streamName), UNO_QUERY);
+ if (!subStream.is())
+ {
+ return "Not Found:";// + streamName;
+ }
+ //The first four byte are the length of the uncompressed data
+ Sequence<sal_Int8> aLength(4);
+ Reference<XSeekable> xSeek(subStream, UNO_QUERY);
+ xSeek->seek(0);
+ //Get the uncompressed length
+ int readbytes = subStream->readBytes(aLength, 4);
+ if (4 != readbytes)
+ {
+ return "Can not read the length.";
+ }
+ sal_Int32 const oleLength = (static_cast<sal_uInt8>(aLength[0]) << 0U)
+ | (static_cast<sal_uInt8>(aLength[1]) << 8U)
+ | (static_cast<sal_uInt8>(aLength[2]) << 16U)
+ | (static_cast<sal_uInt8>(aLength[3]) << 24U);
+ if (oleLength < 0)
+ {
+ return "invalid oleLength";
+ }
+ Sequence<sal_Int8> content(oleLength);
+ //Read all bytes. The compressed length should be less than the uncompressed length
+ readbytes = subStream->readBytes(content, oleLength);
+ if (oleLength < readbytes)
+ {
+ return "oleLength";// +oleLength + readBytes;
+ }
+
+ // Decompress the bytes
+ std::optional< ::ZipUtils::Inflater> decompresser(std::in_place, false);
+ decompresser->setInput(content);
+ Sequence<sal_Int8> result(oleLength);
+ decompresser->doInflateSegment(result, 0, oleLength);
+ decompresser->end();
+ decompresser.reset();
+ //return the base64 string of the uncompressed data
+ OUStringBuffer buf(oleLength);
+ ::comphelper::Base64::encode(buf, result);
+ return OUStringToOString(buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US);
+ }
+
+ void
+ OleHandler::insertByName(const OUString& streamName, std::string_view content)
+ {
+ if ( streamName == "oledata.mso" )
+ {
+ initRootStorageFromBase64(content);
+ }
+ else
+ {
+ ensureCreateRootStorage();
+ insertSubStorage(streamName, content);
+ }
+ }
+
+ OString
+ OleHandler::getByName(const OUString& streamName)
+ {
+ if ( streamName == "oledata.mso" )
+ {
+ //get the length and seek to 0
+ Reference<XSeekable> xSeek (m_rootStream, UNO_QUERY);
+ int oleLength = static_cast<int>(xSeek->getLength());
+ xSeek->seek(0);
+ //read all bytes
+ Reference<XInputStream> xInput = m_rootStream->getInputStream();
+ Sequence<sal_Int8> oledata(oleLength);
+ xInput->readBytes(oledata, oleLength);
+ //return the base64 encoded string
+ OUStringBuffer buf(oleLength);
+ ::comphelper::Base64::encode(buf, oledata);
+ return OUStringToOString(buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US);
+ }
+ return encodeSubStorage(streamName);
+ }
+
+ void
+ OleHandler::insertSubStorage(const OUString& streamName, std::string_view content)
+ {
+ //decode the base64 string
+ Sequence<sal_Int8> oledata;
+ ::comphelper::Base64::decode(oledata,
+ OStringToOUString(content, RTL_TEXTENCODING_ASCII_US));
+ //create a temp stream to write data to
+ Reference<XStream> subStream = createTempFile();
+ Reference<XInputStream> xInput = subStream->getInputStream();
+ Reference<XOutputStream> xOutput = subStream->getOutputStream();
+ //write the length to the temp stream
+ Sequence<sal_Int8> header{
+ static_cast<sal_Int8>((oledata.getLength() >> 0) & 0xFF),
+ static_cast<sal_Int8>((oledata.getLength() >> 8) & 0xFF),
+ static_cast<sal_Int8>((oledata.getLength() >> 16) & 0xFF),
+ static_cast<sal_Int8>((oledata.getLength() >> 24) & 0xFF)
+ };
+ xOutput->writeBytes(header);
+
+ // Compress the bytes
+ Sequence<sal_Int8> output(oledata.getLength());
+ std::optional< ::ZipUtils::Deflater> compresser(std::in_place, sal_Int32(3), false);
+ compresser->setInputSegment(oledata);
+ compresser->finish();
+ int compressedDataLength = compresser->doDeflateSegment(output, oledata.getLength());
+ compresser.reset();
+ //realloc the data length
+ output.realloc(compressedDataLength);
+
+ //write the compressed data to the temp stream
+ xOutput->writeBytes(output);
+ //seek to 0
+ Reference<XSeekable> xSeek(xInput, UNO_QUERY);
+ xSeek->seek(0);
+
+ //insert the temp stream as a sub stream and use an XTransactedObject to commit it immediately
+ Reference<XTransactedObject> xTransact(m_storage, UNO_QUERY);
+ Any entry;
+ entry <<= xInput;
+ m_storage->insertByName(streamName, entry);
+ xTransact->commit();
+ }
+
+
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+