Bump version to 6.4-15
[LibreOffice.git] / filter / source / xsltfilter / OleHandler.cxx
blob265321ec9f8e591dafc2d33ae9bc5517b3f208d7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /*
4 * This file is part of the LibreOffice project.
6 * This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 */
12 #include <cstdio>
13 #include <cstring>
14 #include <list>
15 #include <map>
16 #include <vector>
17 #include <iostream>
18 #include <libxml/parser.h>
19 #include <libxml/tree.h>
20 #include <libxml/xmlIO.h>
21 #include <libxslt/transform.h>
22 #include <libxslt/xsltutils.h>
23 #include <libxslt/variables.h>
25 #include <rtl/ustrbuf.hxx>
27 #include <sax/tools/converter.hxx>
29 #include <package/Inflater.hxx>
30 #include <package/Deflater.hxx>
32 #include <cppuhelper/factory.hxx>
33 #include <comphelper/base64.hxx>
34 #include <com/sun/star/uno/Any.hxx>
35 #include <com/sun/star/uno/XInterface.hpp>
36 #include <com/sun/star/container/XNameContainer.hpp>
37 #include <com/sun/star/io/TempFile.hpp>
38 #include <com/sun/star/io/XInputStream.hpp>
39 #include <com/sun/star/io/XOutputStream.hpp>
40 #include <com/sun/star/io/XSeekable.hpp>
41 #include <com/sun/star/embed/XTransactedObject.hpp>
42 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
44 #include "OleHandler.hxx"
45 #include <memory>
47 using namespace ::com::sun::star::uno;
48 using namespace ::com::sun::star::lang;
49 using namespace ::com::sun::star::io;
50 using namespace ::com::sun::star::embed;
53 namespace XSLT
55 Reference<XStream> OleHandler::createTempFile() {
56 Reference<XStream> tempFile = TempFile::create(m_xContext);
57 OSL_ASSERT(tempFile.is());
58 return tempFile;
61 void OleHandler::ensureCreateRootStorage()
63 if (m_storage == nullptr || m_rootStream == nullptr)
65 m_rootStream = createTempFile();
66 Sequence<Any> args(1);
67 args[0] <<= m_rootStream->getInputStream();
69 Reference<XNameContainer> cont(
70 Reference<XMultiServiceFactory>(m_xContext->getServiceManager(), UNO_QUERY_THROW)
71 ->createInstanceWithArguments("com.sun.star.embed.OLESimpleStorage", args), UNO_QUERY);
72 m_storage = cont;
76 void OleHandler::initRootStorageFromBase64(const OString& content)
78 Sequence<sal_Int8> oleData;
79 ::comphelper::Base64::decode(oleData, OStringToOUString(
80 content, RTL_TEXTENCODING_UTF8));
81 m_rootStream = createTempFile();
82 Reference<XOutputStream> xOutput = m_rootStream->getOutputStream();
83 xOutput->writeBytes(oleData);
84 xOutput->flush();
85 //Get the input stream and seek to begin
86 Reference<XSeekable> xSeek(m_rootStream->getInputStream(), UNO_QUERY);
87 xSeek->seek(0);
89 //create a com.sun.star.embed.OLESimpleStorage from the temp stream
90 Sequence<Any> args(1);
91 args[0] <<= xSeek;
92 Reference<XNameContainer> cont(
93 Reference<XMultiServiceFactory>(m_xContext->getServiceManager(), UNO_QUERY_THROW)
94 ->createInstanceWithArguments("com.sun.star.embed.OLESimpleStorage", args), UNO_QUERY);
95 m_storage = cont;
98 OString
99 OleHandler::encodeSubStorage(const OUString& streamName)
101 if (!m_storage || !m_storage->hasByName(streamName))
103 return "Not Found:";// + streamName;
106 Reference<XInputStream> subStream(m_storage->getByName(streamName), UNO_QUERY);
107 if (!subStream.is())
109 return "Not Found:";// + streamName;
111 //The first four byte are the length of the uncompressed data
112 Sequence<sal_Int8> aLength(4);
113 Reference<XSeekable> xSeek(subStream, UNO_QUERY);
114 xSeek->seek(0);
115 //Get the uncompressed length
116 int readbytes = subStream->readBytes(aLength, 4);
117 if (4 != readbytes)
119 return "Can not read the length.";
121 sal_Int32 const oleLength = (static_cast<sal_uInt8>(aLength[0]) << 0U)
122 | (static_cast<sal_uInt8>(aLength[1]) << 8U)
123 | (static_cast<sal_uInt8>(aLength[2]) << 16U)
124 | (static_cast<sal_uInt8>(aLength[3]) << 24U);
125 if (oleLength < 0)
127 return "invalid oleLength";
129 Sequence<sal_Int8> content(oleLength);
130 //Read all bytes. The compressed length should be less than the uncompressed length
131 readbytes = subStream->readBytes(content, oleLength);
132 if (oleLength < readbytes)
134 return "oleLength";// +oleLength + readBytes;
137 // Decompress the bytes
138 std::unique_ptr< ::ZipUtils::Inflater> decompresser(new ::ZipUtils::Inflater(false));
139 decompresser->setInput(content);
140 Sequence<sal_Int8> result(oleLength);
141 decompresser->doInflateSegment(result, 0, oleLength);
142 decompresser->end();
143 decompresser.reset();
144 //return the base64 string of the uncompressed data
145 OUStringBuffer buf(oleLength);
146 ::comphelper::Base64::encode(buf, result);
147 return OUStringToOString(buf.toString(), RTL_TEXTENCODING_UTF8);
150 void
151 OleHandler::insertByName(const OUString& streamName, const OString& content)
153 if ( streamName == "oledata.mso" )
155 initRootStorageFromBase64(content);
157 else
159 ensureCreateRootStorage();
160 insertSubStorage(streamName, content);
164 OString
165 OleHandler::getByName(const OUString& streamName)
167 if ( streamName == "oledata.mso" )
169 //get the length and seek to 0
170 Reference<XSeekable> xSeek (m_rootStream, UNO_QUERY);
171 int oleLength = static_cast<int>(xSeek->getLength());
172 xSeek->seek(0);
173 //read all bytes
174 Reference<XInputStream> xInput = m_rootStream->getInputStream();
175 Sequence<sal_Int8> oledata(oleLength);
176 xInput->readBytes(oledata, oleLength);
177 //return the base64 encoded string
178 OUStringBuffer buf(oleLength);
179 ::comphelper::Base64::encode(buf, oledata);
180 return OUStringToOString(buf.toString(), RTL_TEXTENCODING_UTF8);
182 return encodeSubStorage(streamName);
185 void
186 OleHandler::insertSubStorage(const OUString& streamName, const OString& content)
188 //decode the base64 string
189 Sequence<sal_Int8> oledata;
190 ::comphelper::Base64::decode(oledata,
191 OStringToOUString(content, RTL_TEXTENCODING_ASCII_US));
192 //create a temp stream to write data to
193 Reference<XStream> subStream = createTempFile();
194 Reference<XInputStream> xInput = subStream->getInputStream();
195 Reference<XOutputStream> xOutput = subStream->getOutputStream();
196 //write the length to the temp stream
197 Sequence<sal_Int8> header(4);
198 header[0] = static_cast<sal_Int8>(oledata.getLength() >> 0) & 0xFF;
199 header[1] = static_cast<sal_Int8>(oledata.getLength() >> 8) & 0xFF;
200 header[2] = static_cast<sal_Int8>(oledata.getLength() >> 16) & 0xFF;
201 header[3] = static_cast<sal_Int8>(oledata.getLength() >> 24) & 0xFF;
202 xOutput->writeBytes(header);
204 // Compress the bytes
205 Sequence<sal_Int8> output(oledata.getLength());
206 std::unique_ptr< ::ZipUtils::Deflater> compresser(new ::ZipUtils::Deflater(sal_Int32(3), false));
207 compresser->setInputSegment(oledata);
208 compresser->finish();
209 int compressedDataLength = compresser->doDeflateSegment(output, oledata.getLength());
210 compresser.reset();
211 //realloc the data length
212 Sequence<sal_Int8> compressed(compressedDataLength);
213 for (int i = 0; i < compressedDataLength; i++) {
214 compressed[i] = output[i];
217 //write the compressed data to the temp stream
218 xOutput->writeBytes(compressed);
219 //seek to 0
220 Reference<XSeekable> xSeek(xInput, UNO_QUERY);
221 xSeek->seek(0);
223 //insert the temp stream as a sub stream and use an XTransactedObject to commit it immediately
224 Reference<XTransactedObject> xTransact(m_storage, UNO_QUERY);
225 Any entry;
226 entry <<= xInput;
227 m_storage->insertByName(streamName, entry);
228 xTransact->commit();
233 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */