/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #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 SAL_CALL OleHandler::createTempFile() { Reference tempFile( TempFile::create(m_xContext), UNO_QUERY); OSL_ASSERT(tempFile.is()); return tempFile; } void SAL_CALL OleHandler::ensureCreateRootStorage() { if (m_storage == nullptr || m_rootStream == nullptr) { m_rootStream = createTempFile(); Sequence args(1); args[0] <<= 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 SAL_CALL OleHandler::initRootStorageFromBase64(const OString& content) { Sequence oleData; ::sax::Converter::decodeBase64(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 an com.sun.star.embed.OLESimpleStorage from the temp stream Sequence args(1); args[0] <<= xSeek; Reference cont( Reference(m_xContext->getServiceManager(), UNO_QUERY_THROW) ->createInstanceWithArguments("com.sun.star.embed.OLESimpleStorage", args), UNO_QUERY); m_storage = cont; } OString SAL_CALL OleHandler::encodeSubStorage(const OUString& streamName) { if (!m_storage->hasByName(streamName)) { return "Not Found:";// + streamName; } ; Reference subStream(*static_cast const *>(m_storage->getByName(streamName).getValue()), 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."; } int oleLength = (aLength[0] << 0) + (aLength[1] << 8) + (aLength[2] << 16) + (aLength[3] << 24); Sequence content(oleLength); //Read all bytes. The compressed length should less then the uncompressed length readbytes = subStream->readBytes(content, oleLength); if (oleLength < readbytes) { return "oleLength";// +oleLength + readBytes; } // Decompress the bytes std::unique_ptr< ::ZipUtils::Inflater> decompresser(new ::ZipUtils::Inflater(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); ::sax::Converter::encodeBase64(buf, result); return OUStringToOString(buf.toString(), RTL_TEXTENCODING_UTF8); } void SAL_CALL OleHandler::insertByName(const OUString& streamName, const OString& content) { if ( streamName == "oledata.mso" ) { initRootStorageFromBase64(content); } else { ensureCreateRootStorage(); insertSubStorage(streamName, content); } } const OString SAL_CALL OleHandler::getByName(const OUString& streamName) { if ( streamName == "oledata.mso" ) { //get the length and seek to 0 Reference xSeek (m_rootStream, UNO_QUERY); int oleLength = (int) 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); ::sax::Converter::encodeBase64(buf, oledata); return OUStringToOString(buf.toString(), RTL_TEXTENCODING_UTF8); } return encodeSubStorage(streamName); } void SAL_CALL OleHandler::insertSubStorage(const OUString& streamName, const OString& content) { //decode the base64 string Sequence oledata; ::sax::Converter::decodeBase64(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(4); header[0] = (sal_Int8) (oledata.getLength() >> 0) & 0xFF; header[1] = (sal_Int8) (oledata.getLength() >> 8) & 0xFF; header[2] = (sal_Int8) (oledata.getLength() >> 16) & 0xFF; header[3] = (sal_Int8) (oledata.getLength() >> 24) & 0xFF; xOutput->writeBytes(header); // Compress the bytes Sequence output(oledata.getLength()); std::unique_ptr< ::ZipUtils::Deflater> compresser(new ::ZipUtils::Deflater((sal_Int32) 3, false)); compresser->setInputSegment(oledata); compresser->finish(); int compressedDataLength = compresser->doDeflateSegment(output, 0, oledata.getLength()); compresser.reset(); //realloc the data length Sequence compressed(compressedDataLength); for (int i = 0; i < compressedDataLength; i++) { compressed[i] = output[i]; } //write the compressed data to the temp stream xOutput->writeBytes(compressed); //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: */