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>
29 #include <osl/diagnose.h>
31 #include <PackageConstants.hxx>
32 #include <ZipEntry.hxx>
33 #include <ZipFile.hxx>
34 #include <ZipPackageBuffer.hxx>
35 #include <ZipPackageStream.hxx>
39 using namespace com::sun::star
;
40 using namespace com::sun::star::io
;
41 using namespace com::sun::star::uno
;
42 using namespace com::sun::star::packages::zip::ZipConstants
;
44 /** This class is used to deflate Zip entries
46 ZipOutputEntry::ZipOutputEntry(
47 const css::uno::Reference
< css::io::XOutputStream
>& rxOutput
,
48 const uno::Reference
< uno::XComponentContext
>& rxContext
,
50 ZipPackageStream
* pStream
,
52 : m_aDeflateBuffer(n_ConstBufferSize
)
53 , m_aDeflater(DEFAULT_COMPRESSION
, true)
54 , m_xContext(rxContext
)
55 , m_xOutStream(rxOutput
)
56 , m_pCurrentEntry(&rEntry
)
58 , m_bEncryptCurrentEntry(bEncrypt
)
59 , m_pCurrentStream(pStream
)
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_bEncryptCurrentEntry(bEncrypt
)
81 , m_pCurrentStream(pStream
)
83 assert(m_pCurrentEntry
->nMethod
== DEFLATED
&& "Use ZipPackageStream::rawWrite() for STORED entries");
84 if (m_bEncryptCurrentEntry
)
86 m_xCipherContext
= ZipFile::StaticGetCipher( m_xContext
, pStream
->GetEncryptionData(), true );
87 m_xDigestContext
= ZipFile::StaticGetDigestContextForChecksum( m_xContext
, pStream
->GetEncryptionData() );
91 ZipOutputEntry::~ZipOutputEntry()
95 void ZipOutputEntry::createBufferFile()
97 assert(!m_xOutStream
.is() && m_aTempURL
.isEmpty() &&
98 "should only be called in the threaded mode where there is no existing stream yet");
99 uno::Reference
< beans::XPropertySet
> xTempFileProps(
100 io::TempFile::create(m_xContext
),
101 uno::UNO_QUERY_THROW
);
102 xTempFileProps
->setPropertyValue("RemoveFile", uno::makeAny(sal_False
));
103 uno::Any aUrl
= xTempFileProps
->getPropertyValue( "Uri" );
105 assert(!m_aTempURL
.isEmpty());
107 uno::Reference
< ucb::XSimpleFileAccess3
> xTempAccess(ucb::SimpleFileAccess::create(m_xContext
));
108 m_xOutStream
= xTempAccess
->openFileWrite(m_aTempURL
);
111 void ZipOutputEntry::closeBufferFile()
113 m_xOutStream
->closeOutput();
114 m_xOutStream
.clear();
117 void ZipOutputEntry::deleteBufferFile()
119 assert(!m_xOutStream
.is() && !m_aTempURL
.isEmpty());
120 uno::Reference
< ucb::XSimpleFileAccess3
> xAccess(ucb::SimpleFileAccess::create(m_xContext
));
121 xAccess
->kill(m_aTempURL
);
124 uno::Reference
< io::XInputStream
> ZipOutputEntry::getData() const
126 uno::Reference
< ucb::XSimpleFileAccess3
> xTempAccess(ucb::SimpleFileAccess::create(m_xContext
));
127 return xTempAccess
->openFileRead(m_aTempURL
);
130 void ZipOutputEntry::closeEntry()
132 m_aDeflater
.finish();
133 while (!m_aDeflater
.finished())
136 if ((m_pCurrentEntry
->nFlag
& 8) == 0)
138 if (m_pCurrentEntry
->nSize
!= m_aDeflater
.getTotalIn())
140 OSL_FAIL("Invalid entry size");
142 if (m_pCurrentEntry
->nCompressedSize
!= m_aDeflater
.getTotalOut())
144 // Different compression strategies make the merit of this
145 // test somewhat dubious
146 m_pCurrentEntry
->nCompressedSize
= m_aDeflater
.getTotalOut();
148 if (m_pCurrentEntry
->nCrc
!= m_aCRC
.getValue())
150 OSL_FAIL("Invalid entry CRC-32");
155 if ( !m_bEncryptCurrentEntry
)
157 m_pCurrentEntry
->nSize
= m_aDeflater
.getTotalIn();
158 m_pCurrentEntry
->nCompressedSize
= m_aDeflater
.getTotalOut();
160 m_pCurrentEntry
->nCrc
= m_aCRC
.getValue();
165 if (m_bEncryptCurrentEntry
)
167 m_xCipherContext
.clear();
169 uno::Sequence
< sal_Int8
> aDigestSeq
;
170 if ( m_xDigestContext
.is() )
172 aDigestSeq
= m_xDigestContext
->finalizeDigestAndDispose();
173 m_xDigestContext
.clear();
176 if ( m_pCurrentStream
)
177 m_pCurrentStream
->setDigest( aDigestSeq
);
181 void ZipOutputEntry::write( const Sequence
< sal_Int8
>& rBuffer
)
183 if (!m_aDeflater
.finished())
185 m_aDeflater
.setInputSegment(rBuffer
);
186 while (!m_aDeflater
.needsInput())
188 if (!m_bEncryptCurrentEntry
)
189 m_aCRC
.updateSegment(rBuffer
, rBuffer
.getLength());
193 void ZipOutputEntry::doDeflate()
195 sal_Int32 nLength
= m_aDeflater
.doDeflateSegment(m_aDeflateBuffer
, 0, m_aDeflateBuffer
.getLength());
199 uno::Sequence
< sal_Int8
> aTmpBuffer( m_aDeflateBuffer
.getConstArray(), nLength
);
200 if ( m_bEncryptCurrentEntry
&& m_xDigestContext
.is() && m_xCipherContext
.is() )
202 // Need to update our digest before encryption...
203 sal_Int32 nDiff
= n_ConstDigestLength
- m_nDigested
;
206 sal_Int32 nEat
= ::std::min( nLength
, nDiff
);
207 uno::Sequence
< sal_Int8
> aTmpSeq( aTmpBuffer
.getConstArray(), nEat
);
208 m_xDigestContext
->updateDigest( aTmpSeq
);
209 m_nDigested
= m_nDigested
+ static_cast< sal_Int16
>( nEat
);
212 // FIXME64: uno::Sequence not 64bit safe.
213 uno::Sequence
< sal_Int8
> aEncryptionBuffer
= m_xCipherContext
->convertWithCipherContext( aTmpBuffer
);
215 m_xOutStream
->writeBytes( aEncryptionBuffer
);
217 // the sizes as well as checksum for encrypted streams is calculated here
218 m_pCurrentEntry
->nCompressedSize
+= aEncryptionBuffer
.getLength();
219 m_pCurrentEntry
->nSize
= m_pCurrentEntry
->nCompressedSize
;
220 m_aCRC
.update( aEncryptionBuffer
);
224 m_xOutStream
->writeBytes ( aTmpBuffer
);
228 if ( m_aDeflater
.finished() && m_bEncryptCurrentEntry
&& m_xDigestContext
.is() && m_xCipherContext
.is() )
230 // FIXME64: sequence not 64bit safe.
231 uno::Sequence
< sal_Int8
> aEncryptionBuffer
= m_xCipherContext
->finalizeCipherContextAndDispose();
232 if ( aEncryptionBuffer
.getLength() )
234 m_xOutStream
->writeBytes( aEncryptionBuffer
);
236 // the sizes as well as checksum for encrypted streams is calculated hier
237 m_pCurrentEntry
->nCompressedSize
+= aEncryptionBuffer
.getLength();
238 m_pCurrentEntry
->nSize
= m_pCurrentEntry
->nCompressedSize
;
239 m_aCRC
.update( aEncryptionBuffer
);
244 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */