/* -*- 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 #include #include #include #include #include #include #include #include "OleHandler.hxx" #include 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 OleHandler::createTempFile() { Reference 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 args{ Any(m_rootStream->getInputStream()) }; Reference cont( Reference(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 oleData; ::comphelper::Base64::decode(oleData, OStringToOUString( content, RTL_TEXTENCODING_UTF8)); m_rootStream = createTempFile(); Reference xOutput = m_rootStream->getOutputStream(); xOutput->writeBytes(oleData); xOutput->flush(); //Get the input stream and seek to begin Reference xSeek(m_rootStream->getInputStream(), UNO_QUERY); xSeek->seek(0); //create a com.sun.star.embed.OLESimpleStorage from the temp stream Sequence args{ Any(xSeek) }; Reference cont( Reference(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 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 aLength(4); Reference 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(aLength[0]) << 0U) | (static_cast(aLength[1]) << 8U) | (static_cast(aLength[2]) << 16U) | (static_cast(aLength[3]) << 24U); if (oleLength < 0) { return "invalid oleLength"; } Sequence 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 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 xSeek (m_rootStream, UNO_QUERY); int oleLength = static_cast(xSeek->getLength()); xSeek->seek(0); //read all bytes Reference xInput = m_rootStream->getInputStream(); Sequence 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 oledata; ::comphelper::Base64::decode(oledata, OStringToOUString(content, RTL_TEXTENCODING_ASCII_US)); //create a temp stream to write data to Reference subStream = createTempFile(); Reference xInput = subStream->getInputStream(); Reference xOutput = subStream->getOutputStream(); //write the length to the temp stream Sequence header{ static_cast((oledata.getLength() >> 0) & 0xFF), static_cast((oledata.getLength() >> 8) & 0xFF), static_cast((oledata.getLength() >> 16) & 0xFF), static_cast((oledata.getLength() >> 24) & 0xFF) }; xOutput->writeBytes(header); // Compress the bytes Sequence 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 xSeek(xInput, UNO_QUERY); xSeek->seek(0); //insert the temp stream as a sub stream and use an XTransactedObject to commit it immediately Reference xTransact(m_storage, UNO_QUERY); Any entry; entry <<= xInput; m_storage->insertByName(streamName, entry); xTransact->commit(); } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */