1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <ZipOutputEntry.hxx>
22 #include <com/sun/star/io/TempFile.hpp>
23 #include <com/sun/star/packages/zip/ZipConstants.hpp>
24 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
25 #include <com/sun/star/ucb/XSimpleFileAccess3.hpp>
26 #include <comphelper/storagehelper.hxx>
28 #include <osl/diagnose.h>
30 #include <PackageConstants.hxx>
31 #include <ZipEntry.hxx>
32 #include <ZipFile.hxx>
33 #include <ZipPackageBuffer.hxx>
34 #include <ZipPackageStream.hxx>
38 using namespace com::sun::star
;
39 using namespace com::sun::star::io
;
40 using namespace com::sun::star::uno
;
41 using namespace com::sun::star::packages::zip::ZipConstants
;
43 /** This class is used to deflate Zip entries
45 ZipOutputEntry::ZipOutputEntry(
46 const css::uno::Reference
< css::io::XOutputStream
>& rxOutput
,
47 const uno::Reference
< uno::XComponentContext
>& rxContext
,
49 ZipPackageStream
* pStream
,
51 : m_aDeflateBuffer(n_ConstBufferSize
)
52 , m_aDeflater(DEFAULT_COMPRESSION
, true)
53 , m_xContext(rxContext
)
54 , m_xOutStream(rxOutput
)
55 , m_pCurrentEntry(&rEntry
)
57 , m_pCurrentStream(pStream
)
58 , m_bEncryptCurrentEntry(bEncrypt
)
61 assert(m_pCurrentEntry
->nMethod
== DEFLATED
&& "Use ZipPackageStream::rawWrite() for STORED entries");
62 assert(m_xOutStream
.is());
63 if (m_bEncryptCurrentEntry
)
65 m_xCipherContext
= ZipFile::StaticGetCipher( m_xContext
, pStream
->GetEncryptionData(), true );
66 m_xDigestContext
= ZipFile::StaticGetDigestContextForChecksum( m_xContext
, pStream
->GetEncryptionData() );
70 ZipOutputEntry::ZipOutputEntry(
71 const uno::Reference
< uno::XComponentContext
>& rxContext
,
73 ZipPackageStream
* pStream
,
75 : m_aDeflateBuffer(n_ConstBufferSize
)
76 , m_aDeflater(DEFAULT_COMPRESSION
, true)
77 , m_xContext(rxContext
)
78 , m_pCurrentEntry(&rEntry
)
80 , m_pCurrentStream(pStream
)
81 , m_bEncryptCurrentEntry(bEncrypt
)
84 assert(m_pCurrentEntry
->nMethod
== DEFLATED
&& "Use ZipPackageStream::rawWrite() for STORED entries");
85 if (m_bEncryptCurrentEntry
)
87 m_xCipherContext
= ZipFile::StaticGetCipher( m_xContext
, pStream
->GetEncryptionData(), true );
88 m_xDigestContext
= ZipFile::StaticGetDigestContextForChecksum( m_xContext
, pStream
->GetEncryptionData() );
92 ZipOutputEntry::~ZipOutputEntry()
96 void ZipOutputEntry::createBufferFile()
98 assert(!m_xOutStream
.is() && m_aTempURL
.isEmpty() &&
99 "should only be called in the threaded mode where there is no existing stream yet");
100 uno::Reference
< beans::XPropertySet
> xTempFileProps(
101 io::TempFile::create(m_xContext
),
102 uno::UNO_QUERY_THROW
);
103 xTempFileProps
->setPropertyValue("RemoveFile", uno::makeAny(false));
104 uno::Any aUrl
= xTempFileProps
->getPropertyValue( "Uri" );
106 assert(!m_aTempURL
.isEmpty());
108 uno::Reference
< ucb::XSimpleFileAccess3
> xTempAccess(ucb::SimpleFileAccess::create(m_xContext
));
109 m_xOutStream
= xTempAccess
->openFileWrite(m_aTempURL
);
112 void ZipOutputEntry::closeBufferFile()
114 m_xOutStream
->closeOutput();
115 m_xOutStream
.clear();
118 void ZipOutputEntry::deleteBufferFile()
120 assert(!m_xOutStream
.is() && !m_aTempURL
.isEmpty());
121 uno::Reference
< ucb::XSimpleFileAccess3
> xAccess(ucb::SimpleFileAccess::create(m_xContext
));
122 xAccess
->kill(m_aTempURL
);
125 uno::Reference
< io::XInputStream
> ZipOutputEntry::getData() const
127 uno::Reference
< ucb::XSimpleFileAccess3
> xTempAccess(ucb::SimpleFileAccess::create(m_xContext
));
128 return xTempAccess
->openFileRead(m_aTempURL
);
131 void ZipOutputEntry::closeEntry()
133 m_aDeflater
.finish();
134 while (!m_aDeflater
.finished())
137 if ((m_pCurrentEntry
->nFlag
& 8) == 0)
139 if (m_pCurrentEntry
->nSize
!= m_aDeflater
.getTotalIn())
141 OSL_FAIL("Invalid entry size");
143 if (m_pCurrentEntry
->nCompressedSize
!= m_aDeflater
.getTotalOut())
145 // Different compression strategies make the merit of this
146 // test somewhat dubious
147 m_pCurrentEntry
->nCompressedSize
= m_aDeflater
.getTotalOut();
149 if (m_pCurrentEntry
->nCrc
!= m_aCRC
.getValue())
151 OSL_FAIL("Invalid entry CRC-32");
156 if ( !m_bEncryptCurrentEntry
)
158 m_pCurrentEntry
->nSize
= m_aDeflater
.getTotalIn();
159 m_pCurrentEntry
->nCompressedSize
= m_aDeflater
.getTotalOut();
161 m_pCurrentEntry
->nCrc
= m_aCRC
.getValue();
166 if (m_bEncryptCurrentEntry
)
168 m_xCipherContext
.clear();
170 uno::Sequence
< sal_Int8
> aDigestSeq
;
171 if ( m_xDigestContext
.is() )
173 aDigestSeq
= m_xDigestContext
->finalizeDigestAndDispose();
174 m_xDigestContext
.clear();
177 if ( m_pCurrentStream
)
178 m_pCurrentStream
->setDigest( aDigestSeq
);
182 void ZipOutputEntry::write( const Sequence
< sal_Int8
>& rBuffer
)
184 if (!m_aDeflater
.finished())
186 m_aDeflater
.setInputSegment(rBuffer
);
187 while (!m_aDeflater
.needsInput())
189 if (!m_bEncryptCurrentEntry
)
190 m_aCRC
.updateSegment(rBuffer
, rBuffer
.getLength());
194 void ZipOutputEntry::doDeflate()
196 sal_Int32 nLength
= m_aDeflater
.doDeflateSegment(m_aDeflateBuffer
, 0, m_aDeflateBuffer
.getLength());
200 uno::Sequence
< sal_Int8
> aTmpBuffer( m_aDeflateBuffer
.getConstArray(), nLength
);
201 if ( m_bEncryptCurrentEntry
&& m_xDigestContext
.is() && m_xCipherContext
.is() )
203 // Need to update our digest before encryption...
204 sal_Int32 nDiff
= n_ConstDigestLength
- m_nDigested
;
207 sal_Int32 nEat
= ::std::min( nLength
, nDiff
);
208 uno::Sequence
< sal_Int8
> aTmpSeq( aTmpBuffer
.getConstArray(), nEat
);
209 m_xDigestContext
->updateDigest( aTmpSeq
);
210 m_nDigested
= m_nDigested
+ static_cast< sal_Int16
>( nEat
);
213 // FIXME64: uno::Sequence not 64bit safe.
214 uno::Sequence
< sal_Int8
> aEncryptionBuffer
= m_xCipherContext
->convertWithCipherContext( aTmpBuffer
);
216 m_xOutStream
->writeBytes( aEncryptionBuffer
);
218 // the sizes as well as checksum for encrypted streams is calculated here
219 m_pCurrentEntry
->nCompressedSize
+= aEncryptionBuffer
.getLength();
220 m_pCurrentEntry
->nSize
= m_pCurrentEntry
->nCompressedSize
;
221 m_aCRC
.update( aEncryptionBuffer
);
225 m_xOutStream
->writeBytes ( aTmpBuffer
);
229 if ( m_aDeflater
.finished() && m_bEncryptCurrentEntry
&& m_xDigestContext
.is() && m_xCipherContext
.is() )
231 // FIXME64: sequence not 64bit safe.
232 uno::Sequence
< sal_Int8
> aEncryptionBuffer
= m_xCipherContext
->finalizeCipherContextAndDispose();
233 if ( aEncryptionBuffer
.getLength() )
235 m_xOutStream
->writeBytes( aEncryptionBuffer
);
237 // the sizes as well as checksum for encrypted streams is calculated hier
238 m_pCurrentEntry
->nCompressedSize
+= aEncryptionBuffer
.getLength();
239 m_pCurrentEntry
->nSize
= m_pCurrentEntry
->nCompressedSize
;
240 m_aCRC
.update( aEncryptionBuffer
);
245 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */