1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
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"
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
;
55 Reference
<XStream
> OleHandler::createTempFile() {
56 Reference
<XStream
> tempFile
= TempFile::create(m_xContext
);
57 OSL_ASSERT(tempFile
.is());
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
);
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
);
85 //Get the input stream and seek to begin
86 Reference
<XSeekable
> xSeek(m_rootStream
->getInputStream(), UNO_QUERY
);
89 //create a com.sun.star.embed.OLESimpleStorage from the temp stream
90 Sequence
<Any
> args(1);
92 Reference
<XNameContainer
> cont(
93 Reference
<XMultiServiceFactory
>(m_xContext
->getServiceManager(), UNO_QUERY_THROW
)
94 ->createInstanceWithArguments("com.sun.star.embed.OLESimpleStorage", args
), UNO_QUERY
);
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
);
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
);
115 //Get the uncompressed length
116 int readbytes
= subStream
->readBytes(aLength
, 4);
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);
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
);
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
);
151 OleHandler::insertByName(const OUString
& streamName
, const OString
& content
)
153 if ( streamName
== "oledata.mso" )
155 initRootStorageFromBase64(content
);
159 ensureCreateRootStorage();
160 insertSubStorage(streamName
, content
);
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());
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
);
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());
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
);
220 Reference
<XSeekable
> xSeek(xInput
, UNO_QUERY
);
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
);
227 m_storage
->insertByName(streamName
, entry
);
233 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */