LibreOffice Module package (master) 1
ZipOutputEntry.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <ZipOutputEntry.hxx>
21
22#include <com/sun/star/io/TempFile.hpp>
23#include <com/sun/star/packages/zip/ZipConstants.hpp>
24
25#include <osl/diagnose.h>
26
27#include <PackageConstants.hxx>
28#include <ThreadedDeflater.hxx>
29#include <ZipEntry.hxx>
30#include <ZipFile.hxx>
31#include <ZipPackageStream.hxx>
32
33#include <algorithm>
34#include <utility>
35
36using namespace com::sun::star;
37using namespace com::sun::star::io;
38using namespace com::sun::star::uno;
39using namespace com::sun::star::packages::zip::ZipConstants;
40
44 css::uno::Reference< css::io::XOutputStream > xOutput,
45 uno::Reference< uno::XComponentContext > xContext,
46 ZipEntry& rEntry,
47 ZipPackageStream* pStream,
48 bool bEncrypt,
49 bool checkStream)
50: m_xContext(std::move(xContext))
51, m_xOutStream(std::move(xOutput))
52, m_pCurrentEntry(&rEntry)
53, m_nDigested(0)
54, m_pCurrentStream(pStream)
55, m_bEncryptCurrentEntry(bEncrypt)
56{
57 assert(m_pCurrentEntry->nMethod == DEFLATED && "Use ZipPackageStream::rawWrite() for STORED entries");
58 (void)checkStream;
59 assert(!checkStream || m_xOutStream.is());
61 {
62 m_xCipherContext = ZipFile::StaticGetCipher( m_xContext, pStream->GetEncryptionData(), true );
63 m_xDigestContext = ZipFile::StaticGetDigestContextForChecksum( m_xContext, pStream->GetEncryptionData() );
64 }
65}
66
68{
70
71 if ((m_pCurrentEntry->nFlag & 8) == 0)
72 {
74 {
75 OSL_FAIL("Invalid entry size");
76 }
78 {
79 // Different compression strategies make the merit of this
80 // test somewhat dubious
82 }
84 {
85 OSL_FAIL("Invalid entry CRC-32");
86 }
87 }
88 else
89 {
91 {
94 }
96 }
98 m_aCRC.reset();
99
101 return;
102
103 m_xCipherContext.clear();
104
105 uno::Sequence< sal_Int8 > aDigestSeq;
106 if ( m_xDigestContext.is() )
107 {
108 aDigestSeq = m_xDigestContext->finalizeDigestAndDispose();
109 m_xDigestContext.clear();
110 }
111
112 if ( m_pCurrentStream )
113 m_pCurrentStream->setDigest( aDigestSeq );
114}
115
116void ZipOutputEntryBase::processDeflated( const uno::Sequence< sal_Int8 >& deflateBuffer, sal_Int32 nLength )
117{
118 if ( nLength > 0 )
119 {
120 uno::Sequence< sal_Int8 > aTmpBuffer( deflateBuffer.getConstArray(), nLength );
122 {
123 // Need to update our digest before encryption...
124 sal_Int32 nDiff = n_ConstDigestLength - m_nDigested;
125 if ( nDiff )
126 {
127 sal_Int32 nEat = ::std::min( nLength, nDiff );
128 uno::Sequence< sal_Int8 > aTmpSeq( aTmpBuffer.getConstArray(), nEat );
129 m_xDigestContext->updateDigest( aTmpSeq );
130 m_nDigested = m_nDigested + static_cast< sal_Int16 >( nEat );
131 }
132
133 // FIXME64: uno::Sequence not 64bit safe.
134 uno::Sequence< sal_Int8 > aEncryptionBuffer = m_xCipherContext->convertWithCipherContext( aTmpBuffer );
135
136 m_xOutStream->writeBytes( aEncryptionBuffer );
137
138 // the sizes as well as checksum for encrypted streams is calculated here
139 m_pCurrentEntry->nCompressedSize += aEncryptionBuffer.getLength();
141 m_aCRC.update( aEncryptionBuffer );
142 }
143 else
144 {
145 m_xOutStream->writeBytes ( aTmpBuffer );
146 }
147 }
148
150 return;
151
152 // FIXME64: sequence not 64bit safe.
153 uno::Sequence< sal_Int8 > aEncryptionBuffer = m_xCipherContext->finalizeCipherContextAndDispose();
154 if ( aEncryptionBuffer.hasElements() )
155 {
156 m_xOutStream->writeBytes( aEncryptionBuffer );
157
158 // the sizes as well as checksum for encrypted streams are calculated here
159 m_pCurrentEntry->nCompressedSize += aEncryptionBuffer.getLength();
161 m_aCRC.update( aEncryptionBuffer );
162 }
163}
164
165void ZipOutputEntryBase::processInput( const uno::Sequence< sal_Int8 >& rBuffer )
166{
168 m_aCRC.updateSegment(rBuffer, rBuffer.getLength());
169}
170
172 const css::uno::Reference< css::io::XOutputStream >& rxOutput,
173 const uno::Reference< uno::XComponentContext >& rxContext,
174 ZipEntry& rEntry,
175 ZipPackageStream* pStream,
176 bool bEncrypt,
177 bool checkStream)
178: ZipOutputEntryBase(rxOutput, rxContext, rEntry, pStream, bEncrypt, checkStream)
179, m_aDeflateBuffer(n_ConstBufferSize)
180, m_aDeflater(DEFAULT_COMPRESSION, true)
181{
182}
183
185 const css::uno::Reference< css::io::XOutputStream >& rxOutput,
186 const uno::Reference< uno::XComponentContext >& rxContext,
187 ZipEntry& rEntry,
188 ZipPackageStream* pStream,
189 bool bEncrypt)
190: ZipOutputEntry( rxOutput, rxContext, rEntry, pStream, bEncrypt, true)
191{
192}
193
195{
196 if (!m_aDeflater.finished())
197 {
199 while (!m_aDeflater.needsInput())
200 doDeflate();
201 processInput(rBuffer);
202 }
203}
204
206{
209}
210
212{
214 while (!m_aDeflater.finished())
215 doDeflate();
216}
217
219{
220 return m_aDeflater.getTotalIn();
221}
222
224{
225 return m_aDeflater.getTotalOut();
226}
227
229{
231}
232
234{
235 return m_aDeflater.finished();
236}
237
238
240 const uno::Reference< uno::XComponentContext >& rxContext,
241 ZipEntry& rEntry,
242 ZipPackageStream* pStream,
243 bool bEncrypt)
244: ZipOutputEntry( uno::Reference< css::io::XOutputStream >(), rxContext, rEntry, pStream, bEncrypt, false )
245, m_bFinished(false)
246{
247}
248
250{
251 assert(!m_xOutStream && !m_xTempFile &&
252 "should only be called in the threaded mode where there is no existing stream yet");
254 m_xOutStream = m_xTempFile->getOutputStream();
255}
256
258{
259 m_xOutStream->closeOutput();
260 m_xOutStream.clear();
261}
262
264{
265 assert(!m_xOutStream.is() && m_xTempFile);
266 m_xTempFile.clear();
267}
268
269uno::Reference< io::XInputStream > ZipOutputEntryInThread::getData() const
270{
271 return m_xTempFile->getInputStream();
272}
273
275{
277 uno::Reference< io::XInputStream > mxInStream;
278
279public:
280 Task( const std::shared_ptr<comphelper::ThreadTaskTag>& pTag, ZipOutputEntryInThread *pEntry,
281 uno::Reference< io::XInputStream > xInStream )
282 : comphelper::ThreadTask(pTag)
283 , mpEntry(pEntry)
284 , mxInStream(std::move(xInStream))
285 {}
286
287private:
288 virtual void doWork() override
289 {
290 try
291 {
294 mxInStream.clear();
297 }
298 catch (...)
299 {
300 mpEntry->setParallelDeflateException(std::current_exception());
301 try
302 {
303 if (mpEntry->m_xOutStream.is())
305 if (mpEntry->m_xTempFile)
307 }
308 catch (uno::Exception const&)
309 {
310 }
312 }
313 }
314};
315
316std::unique_ptr<comphelper::ThreadTask> ZipOutputEntryInThread::createTask(
317 const std::shared_ptr<comphelper::ThreadTaskTag>& pTag,
318 const uno::Reference< io::XInputStream >& xInStream )
319{
320 return std::make_unique<Task>(pTag, this, xInStream);
321}
322
323void ZipOutputEntry::writeStream(const uno::Reference< io::XInputStream >& xInStream)
324{
325 sal_Int32 nLength = 0;
326 uno::Sequence< sal_Int8 > aSeq(n_ConstBufferSize);
327 do
328 {
329 nLength = xInStream->readBytes(aSeq, n_ConstBufferSize);
331 aSeq.realloc(nLength);
332
333 write(aSeq);
334 }
335 while (nLength == n_ConstBufferSize);
336 closeEntry();
337}
338
339
341 const css::uno::Reference< css::io::XOutputStream >& rxOutput,
342 const uno::Reference< uno::XComponentContext >& rxContext,
343 ZipEntry& rEntry,
344 ZipPackageStream* pStream,
345 bool bEncrypt)
346: ZipOutputEntryBase(rxOutput, rxContext, rEntry, pStream, bEncrypt, true)
347, totalIn(0)
348, totalOut(0)
349, finished(false)
350{
351}
352
353void ZipOutputEntryParallel::writeStream(const uno::Reference< io::XInputStream >& xInStream)
354{
355 ZipUtils::ThreadedDeflater deflater( DEFAULT_COMPRESSION );
356 deflater.deflateWrite(xInStream,
357 [this](const uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nLen) {
359 m_aCRC.updateSegment(rBuffer, nLen);
360 },
361 [this](const uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nLen) {
362 processDeflated(rBuffer, nLen);
363 }
364 );
365 finished = true;
366 processDeflated( uno::Sequence< sal_Int8 >(), 0 ); // finish encrypting, etc.
367 totalIn = deflater.getTotalIn();
368 totalOut = deflater.getTotalOut();
369 closeEntry();
370}
371
373{
374 // ThreadedDeflater is called synchronously in one call, so nothing to do here.
375}
376
378{
379 return totalIn;
380}
381
383{
384 return totalOut;
385}
386
388{
389 totalIn = 0;
390 totalOut = 0;
391 finished = false;
392}
393
395{
396 return finished;
397}
398
399/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< XComponentContext > m_xContext
const sal_Int32 n_ConstDigestLength
const sal_Int32 n_ConstBufferSize
sal_Int32 getValue() const
Definition: CRC32.cxx:39
void updateSegment(const css::uno::Sequence< sal_Int8 > &b, sal_Int32 len)
Update CRC32 with specified sequence of bytes.
Definition: CRC32.cxx:45
void update(const css::uno::Sequence< sal_Int8 > &b)
Update CRC32 with specified sequence of bytes.
Definition: CRC32.cxx:51
void reset()
Definition: CRC32.cxx:35
css::uno::Reference< css::io::XOutputStream > m_xOutStream
virtual sal_Int64 getDeflaterTotalIn() const =0
void processInput(const css::uno::Sequence< sal_Int8 > &rBuffer)
ZipEntry * m_pCurrentEntry
css::uno::Reference< css::uno::XComponentContext > m_xContext
ZipPackageStream * m_pCurrentStream
css::uno::Reference< css::xml::crypto::XDigestContext > m_xDigestContext
css::uno::Reference< css::xml::crypto::XCipherContext > m_xCipherContext
void processDeflated(const css::uno::Sequence< sal_Int8 > &deflateBuffer, sal_Int32 nLength)
virtual void finishDeflater()=0
virtual bool isDeflaterFinished() const =0
virtual sal_Int64 getDeflaterTotalOut() const =0
virtual void deflaterReset()=0
ZipOutputEntryBase(css::uno::Reference< css::io::XOutputStream > xOutStream, css::uno::Reference< css::uno::XComponentContext > xContext, ZipEntry &rEntry, ZipPackageStream *pStream, bool bEncrypt, bool checkStream)
This class is used to deflate Zip entries.
uno::Reference< io::XInputStream > mxInStream
Task(const std::shared_ptr< comphelper::ThreadTaskTag > &pTag, ZipOutputEntryInThread *pEntry, uno::Reference< io::XInputStream > xInStream)
virtual void doWork() override
ZipOutputEntryInThread * mpEntry
std::unique_ptr< comphelper::ThreadTask > createTask(const std::shared_ptr< comphelper::ThreadTaskTag > &pTag, const css::uno::Reference< css::io::XInputStream > &xInStream)
ZipOutputEntryInThread(const css::uno::Reference< css::uno::XComponentContext > &rxContext, ZipEntry &rEntry, ZipPackageStream *pStream, bool bEncrypt)
rtl::Reference< utl::TempFileFastService > m_xTempFile
css::uno::Reference< css::io::XInputStream > getData() const
void setParallelDeflateException(const std::exception_ptr &exception)
virtual void finishDeflater() override
virtual void deflaterReset() override
ZipOutputEntryParallel(const css::uno::Reference< css::io::XOutputStream > &rxOutStream, const css::uno::Reference< css::uno::XComponentContext > &rxContext, ZipEntry &rEntry, ZipPackageStream *pStream, bool bEncrypt)
virtual bool isDeflaterFinished() const override
void writeStream(const css::uno::Reference< css::io::XInputStream > &xInStream) override
virtual sal_Int64 getDeflaterTotalIn() const override
virtual sal_Int64 getDeflaterTotalOut() const override
ZipOutputEntry(const css::uno::Reference< css::io::XOutputStream > &rxOutStream, const css::uno::Reference< css::uno::XComponentContext > &rxContext, ZipEntry &rEntry, ZipPackageStream *pStream, bool bEncrypt)
virtual sal_Int64 getDeflaterTotalIn() const override
virtual void finishDeflater() override
virtual bool isDeflaterFinished() const override
virtual void deflaterReset() override
ZipUtils::Deflater m_aDeflater
void writeStream(const css::uno::Reference< css::io::XInputStream > &xInStream) override
void write(const css::uno::Sequence< sal_Int8 > &rBuffer)
virtual sal_Int64 getDeflaterTotalOut() const override
css::uno::Sequence< sal_Int8 > m_aDeflateBuffer
void setDigest(const css::uno::Sequence< sal_Int8 > &rNewDigest)
::rtl::Reference< EncryptionData > GetEncryptionData(Bugs bugs=Bugs::None)
sal_Int64 getTotalOut() const
Definition: Deflater.cxx:134
bool finished() const
Definition: Deflater.hxx:52
bool needsInput() const
Definition: Deflater.cxx:117
sal_Int64 getTotalIn() const
Definition: Deflater.cxx:130
sal_Int32 doDeflateSegment(css::uno::Sequence< sal_Int8 > &rBuffer, sal_Int32 nNewLength)
Definition: Deflater.cxx:125
void setInputSegment(const css::uno::Sequence< sal_Int8 > &rBuffer)
Definition: Deflater.cxx:110
Parallel compression a stream using the libz deflate algorithm.
void deflateWrite(const css::uno::Reference< css::io::XInputStream > &xInStream, std::function< void(const css::uno::Sequence< sal_Int8 > &, sal_Int32)> aProcessInputFunc, std::function< void(const css::uno::Sequence< sal_Int8 > &, sal_Int32)> aProcessOutputFunc)
ThreadTask(std::shared_ptr< ThreadTaskTag > pTag)
Sequence< sal_Int8 > aSeq
sal_Int64 nCompressedSize
Definition: ZipEntry.hxx:31
sal_Int32 nCrc
Definition: ZipEntry.hxx:30
sal_Int64 nSize
Definition: ZipEntry.hxx:32
sal_Int16 nFlag
Definition: ZipEntry.hxx:27
sal_Int16 nMethod
Definition: ZipEntry.hxx:28
sal_Int32 nLength