Branch data Line data Source code
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 <string.h>
21 : :
22 : : #include <ZipPackageFolder.hxx>
23 : : #include <ZipFile.hxx>
24 : : #include <ZipOutputStream.hxx>
25 : : #include <ZipPackageStream.hxx>
26 : : #include <PackageConstants.hxx>
27 : : #include <ZipPackageFolderEnumeration.hxx>
28 : : #include <com/sun/star/packages/zip/ZipConstants.hpp>
29 : : #include <com/sun/star/embed/StorageFormats.hpp>
30 : : #include <osl/diagnose.h>
31 : : #include <osl/time.h>
32 : : #include <rtl/digest.h>
33 : : #include <ContentInfo.hxx>
34 : : #include <com/sun/star/beans/PropertyValue.hpp>
35 : : #include <com/sun/star/io/XSeekable.hpp>
36 : : #include <EncryptedDataHeader.hxx>
37 : : #include <rtl/random.h>
38 : : #include <rtl/instance.hxx>
39 : : #include <memory>
40 : :
41 : : using namespace com::sun::star;
42 : : using namespace com::sun::star::packages::zip::ZipConstants;
43 : : using namespace com::sun::star::packages::zip;
44 : : using namespace com::sun::star::packages;
45 : : using namespace com::sun::star::container;
46 : : using namespace com::sun::star::beans;
47 : : using namespace com::sun::star::lang;
48 : : using namespace com::sun::star::io;
49 : : using namespace cppu;
50 : : using namespace std;
51 : : using namespace ::com::sun::star;
52 : :
53 : : namespace { struct lcl_CachedImplId : public rtl::Static< uno::Sequence < sal_Int8 >, lcl_CachedImplId > {}; }
54 : :
55 : 43074 : ZipPackageFolder::ZipPackageFolder ( const uno::Reference< XMultiServiceFactory >& xFactory,
56 : : sal_Int32 nFormat,
57 : : sal_Bool bAllowRemoveOnInsert )
58 : : : m_xFactory( xFactory )
59 [ + - ]: 43074 : , m_nFormat( nFormat )
60 : : {
61 : : OSL_ENSURE( m_xFactory.is(), "No factory is provided to the package folder!" );
62 : :
63 : 43074 : this->mbAllowRemoveOnInsert = bAllowRemoveOnInsert;
64 : :
65 : 43074 : SetFolder ( sal_True );
66 : 43074 : aEntry.nVersion = -1;
67 : 43074 : aEntry.nFlag = 0;
68 : 43074 : aEntry.nMethod = STORED;
69 : 43074 : aEntry.nTime = -1;
70 : 43074 : aEntry.nCrc = 0;
71 : 43074 : aEntry.nCompressedSize = 0;
72 : 43074 : aEntry.nSize = 0;
73 : 43074 : aEntry.nOffset = -1;
74 [ + - ]: 43074 : uno::Sequence < sal_Int8 > &rCachedImplId = lcl_CachedImplId::get();
75 [ + + ]: 43074 : if ( !rCachedImplId.getLength() )
76 [ + - ][ + - ]: 187 : rCachedImplId = getImplementationId();
[ + - ]
77 : 43074 : }
78 : :
79 : :
80 [ + - ]: 41019 : ZipPackageFolder::~ZipPackageFolder()
81 : : {
82 [ - + ]: 82038 : }
83 : :
84 : 5403 : sal_Bool ZipPackageFolder::LookForUnexpectedODF12Streams( const OUString& aPath )
85 : : {
86 : 5403 : sal_Bool bHasUnexpected = sal_False;
87 : :
88 [ + - ][ + - ]: 26528 : for ( ContentHash::const_iterator aCI = maContents.begin(), aEnd = maContents.end();
[ + - + + ]
[ + + ]
89 : 13264 : !bHasUnexpected && aCI != aEnd;
90 : : ++aCI)
91 : : {
92 [ + - ]: 7861 : const OUString &rShortName = (*aCI).first;
93 [ + - ]: 7861 : const ContentInfo &rInfo = *(*aCI).second;
94 : :
95 [ + + ]: 7861 : if ( rInfo.bFolder )
96 : : {
97 [ - + ]: 4826 : if ( aPath == "META-INF/" )
98 : : {
99 : : // META-INF is not allowed to contain subfolders
100 : 0 : bHasUnexpected = sal_True;
101 : : }
102 : : else
103 : : {
104 : 4826 : OUString sOwnPath = aPath + rShortName + "/";
105 [ + - ]: 4826 : bHasUnexpected = rInfo.pFolder->LookForUnexpectedODF12Streams( sOwnPath );
106 : : }
107 : : }
108 : : else
109 : : {
110 [ - + ]: 3035 : if ( aPath == "META-INF/" )
111 : : {
112 [ # # # # ]: 0 : if ( rShortName != "manifest.xml"
[ # # ]
113 : 0 : && rShortName.indexOf( "signatures" ) == -1 )
114 : : {
115 : : // a stream from META-INF with unexpected name
116 : 0 : bHasUnexpected = sal_True;
117 : : }
118 : :
119 : : // streams from META-INF with expected names are allowed not to be registered in manifest.xml
120 : : }
121 [ - + ]: 3035 : else if ( !rInfo.pStream->IsFromManifest() )
122 : : {
123 : : // the stream is not in META-INF and ist notregistered in manifest.xml,
124 : : // check whether it is an internal part of the package format
125 [ # # ][ # # ]: 0 : if ( !aPath.isEmpty() || rShortName != "mimetype" )
[ # # ]
126 : : {
127 : : // if it is not "mimetype" from the root it is not a part of the package
128 : 0 : bHasUnexpected = sal_True;
129 : : }
130 : : }
131 : : }
132 : : }
133 : :
134 : 5403 : return bHasUnexpected;
135 : : }
136 : :
137 : 2469 : void ZipPackageFolder::setChildStreamsTypeByExtension( const beans::StringPair& aPair )
138 : : {
139 : 2469 : OUString aExt;
140 [ - + ]: 2469 : if ( aPair.First.toChar() == (sal_Unicode)'.' )
141 : 0 : aExt = aPair.First;
142 : : else
143 : 2469 : aExt = "." + aPair.First;
144 : :
145 [ + - ][ + - ]: 9527 : for ( ContentHash::const_iterator aCI = maContents.begin(), aEnd = maContents.end();
[ + + ]
146 : : aCI != aEnd;
147 : : ++aCI)
148 : : {
149 [ + - ]: 7058 : const OUString &rShortName = (*aCI).first;
150 [ + - ]: 7058 : const ContentInfo &rInfo = *(*aCI).second;
151 : :
152 [ + + ]: 7058 : if ( rInfo.bFolder )
153 [ + - ]: 2092 : rInfo.pFolder->setChildStreamsTypeByExtension( aPair );
154 : : else
155 : : {
156 : 4966 : sal_Int32 nPathLength = rShortName.getLength();
157 : 4966 : sal_Int32 nExtLength = aExt.getLength();
158 [ + + ][ + + ]: 4966 : if ( nPathLength >= nExtLength && rShortName.match( aExt, nPathLength - nExtLength ) )
[ + - ]
159 : 2186 : rInfo.pStream->SetMediaType( aPair.Second );
160 : : }
161 : 2469 : }
162 : 2469 : }
163 : :
164 : 3006 : void ZipPackageFolder::copyZipEntry( ZipEntry &rDest, const ZipEntry &rSource)
165 : : {
166 : 3006 : rDest.nVersion = rSource.nVersion;
167 : 3006 : rDest.nFlag = rSource.nFlag;
168 : 3006 : rDest.nMethod = rSource.nMethod;
169 : 3006 : rDest.nTime = rSource.nTime;
170 : 3006 : rDest.nCrc = rSource.nCrc;
171 : 3006 : rDest.nCompressedSize = rSource.nCompressedSize;
172 : 3006 : rDest.nSize = rSource.nSize;
173 : 3006 : rDest.nOffset = rSource.nOffset;
174 : 3006 : rDest.sPath = rSource.sPath;
175 : 3006 : rDest.nPathLen = rSource.nPathLen;
176 : 3006 : rDest.nExtraLen = rSource.nExtraLen;
177 : 3006 : }
178 : :
179 : 18860 : const ::com::sun::star::uno::Sequence < sal_Int8 >& ZipPackageFolder::static_getImplementationId()
180 : : {
181 : 18860 : return lcl_CachedImplId::get();
182 : : }
183 : :
184 : : // XNameContainer
185 : 4033 : void SAL_CALL ZipPackageFolder::insertByName( const OUString& aName, const uno::Any& aElement )
186 : : throw(IllegalArgumentException, ElementExistException, WrappedTargetException, uno::RuntimeException)
187 : : {
188 [ - + ]: 4033 : if (hasByName(aName))
189 [ # # ]: 0 : throw ElementExistException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
190 : : else
191 : : {
192 : 4033 : uno::Reference < XUnoTunnel > xRef;
193 [ + - ]: 4033 : aElement >>= xRef;
194 [ + - ][ + - ]: 4033 : if ( ( aElement >>= xRef ) )
195 : : {
196 : : sal_Int64 nTest;
197 : : ZipPackageEntry *pEntry;
198 [ + - ][ + - ]: 4033 : if ( ( nTest = xRef->getSomething ( ZipPackageFolder::static_getImplementationId() ) ) != 0 )
[ + - ][ + + ]
199 : : {
200 : 736 : ZipPackageFolder *pFolder = reinterpret_cast < ZipPackageFolder * > ( nTest );
201 : 736 : pEntry = static_cast < ZipPackageEntry * > ( pFolder );
202 : : }
203 [ + - ][ + - ]: 3297 : else if ( ( nTest = xRef->getSomething ( ZipPackageStream::static_getImplementationId() ) ) != 0 )
[ + - ][ + - ]
204 : : {
205 : 3297 : ZipPackageStream *pStream = reinterpret_cast < ZipPackageStream * > ( nTest );
206 : 3297 : pEntry = static_cast < ZipPackageEntry * > ( pStream );
207 : : }
208 : : else
209 [ # # ]: 0 : throw IllegalArgumentException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >(), 0 );
210 : :
211 [ + - ][ + + ]: 4033 : if (pEntry->getName() != aName )
212 [ + - ]: 4031 : pEntry->setName (aName);
213 [ + - ]: 4033 : doInsertByName ( pEntry, sal_True );
214 : : }
215 : : else
216 [ # # ]: 4033 : throw IllegalArgumentException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >(), 0 );
217 : : }
218 : 4033 : }
219 : 1821 : void SAL_CALL ZipPackageFolder::removeByName( const OUString& Name )
220 : : throw(NoSuchElementException, WrappedTargetException, uno::RuntimeException)
221 : : {
222 [ + - ]: 1821 : ContentHash::iterator aIter = maContents.find ( Name );
223 [ + - ][ - + ]: 1821 : if ( aIter == maContents.end() )
224 [ # # ]: 0 : throw NoSuchElementException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
225 [ + - ]: 1821 : maContents.erase( aIter );
226 : 1821 : }
227 : : // XEnumerationAccess
228 : 20404 : uno::Reference< XEnumeration > SAL_CALL ZipPackageFolder::createEnumeration( )
229 : : throw(uno::RuntimeException)
230 : : {
231 [ + - ][ + - ]: 20404 : return uno::Reference < XEnumeration> (new ZipPackageFolderEnumeration(maContents));
232 : : }
233 : : // XElementAccess
234 : 0 : uno::Type SAL_CALL ZipPackageFolder::getElementType( )
235 : : throw(uno::RuntimeException)
236 : : {
237 : 0 : return ::getCppuType ((const uno::Reference< XUnoTunnel > *) 0);
238 : : }
239 : 0 : sal_Bool SAL_CALL ZipPackageFolder::hasElements( )
240 : : throw(uno::RuntimeException)
241 : : {
242 : 0 : return maContents.size() > 0;
243 : : }
244 : : // XNameAccess
245 : 21658 : ContentInfo& ZipPackageFolder::doGetByName( const OUString& aName )
246 : : throw(NoSuchElementException, WrappedTargetException, uno::RuntimeException)
247 : : {
248 [ + - ]: 21658 : ContentHash::iterator aIter = maContents.find ( aName );
249 [ + - ][ - + ]: 21658 : if ( aIter == maContents.end())
250 [ # # ]: 0 : throw NoSuchElementException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
251 [ + - ]: 21658 : return *(*aIter).second;
252 : : }
253 : 15827 : uno::Any SAL_CALL ZipPackageFolder::getByName( const OUString& aName )
254 : : throw(NoSuchElementException, WrappedTargetException, uno::RuntimeException)
255 : : {
256 : 15827 : return uno::makeAny ( doGetByName ( aName ).xTunnel );
257 : : }
258 : 0 : uno::Sequence< OUString > SAL_CALL ZipPackageFolder::getElementNames( )
259 : : throw(uno::RuntimeException)
260 : : {
261 : 0 : sal_uInt32 i=0, nSize = maContents.size();
262 : 0 : uno::Sequence < OUString > aSequence ( nSize );
263 [ # # ][ # # ]: 0 : for ( ContentHash::const_iterator aIterator = maContents.begin(), aEnd = maContents.end();
[ # # ]
264 : : aIterator != aEnd;
265 : : ++i, ++aIterator)
266 [ # # ][ # # ]: 0 : aSequence[i] = (*aIterator).first;
267 : 0 : return aSequence;
268 : : }
269 : 62954 : sal_Bool SAL_CALL ZipPackageFolder::hasByName( const OUString& aName )
270 : : throw(uno::RuntimeException)
271 : : {
272 [ + - ]: 62954 : return maContents.find ( aName ) != maContents.end ();
273 : : }
274 : : // XNameReplace
275 : 0 : void SAL_CALL ZipPackageFolder::replaceByName( const OUString& aName, const uno::Any& aElement )
276 : : throw(IllegalArgumentException, NoSuchElementException, WrappedTargetException, uno::RuntimeException)
277 : : {
278 [ # # ]: 0 : if ( hasByName( aName ) )
279 : 0 : removeByName( aName );
280 : : else
281 [ # # ]: 0 : throw NoSuchElementException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
282 : 0 : insertByName(aName, aElement);
283 : 0 : }
284 : :
285 : 76 : static void ImplSetStoredData( ZipEntry & rEntry, uno::Reference< XInputStream> & rStream )
286 : : {
287 : : // It's very annoying that we have to do this, but lots of zip packages
288 : : // don't allow data descriptors for STORED streams, meaning we have to
289 : : // know the size and CRC32 of uncompressed streams before we actually
290 : : // write them !
291 [ + - ]: 76 : CRC32 aCRC32;
292 : 76 : rEntry.nMethod = STORED;
293 [ + - ]: 76 : rEntry.nCompressedSize = rEntry.nSize = aCRC32.updateStream ( rStream );
294 [ + - ][ + - ]: 76 : rEntry.nCrc = aCRC32.getValue();
295 : 76 : }
296 : :
297 : 2250 : bool ZipPackageFolder::saveChild( const OUString &rShortName, const ContentInfo &rInfo, OUString &rPath, std::vector < uno::Sequence < PropertyValue > > &rManList, ZipOutputStream & rZipOut, const uno::Sequence < sal_Int8 >& rEncryptionKey, rtlRandomPool &rRandomPool)
298 : : {
299 : 2250 : bool bSuccess = true;
300 : :
301 : 2250 : const OUString sMediaTypeProperty ("MediaType");
302 : 2250 : const OUString sVersionProperty ("Version");
303 : 2250 : const OUString sFullPathProperty ("FullPath");
304 : 2250 : const OUString sInitialisationVectorProperty ("InitialisationVector");
305 : 2250 : const OUString sSaltProperty ("Salt");
306 : 2250 : const OUString sIterationCountProperty ("IterationCount");
307 : 2250 : const OUString sSizeProperty ("Size");
308 : 2250 : const OUString sDigestProperty ("Digest");
309 : 2250 : const OUString sEncryptionAlgProperty ("EncryptionAlgorithm");
310 : 2250 : const OUString sStartKeyAlgProperty ("StartKeyAlgorithm");
311 : 2250 : const OUString sDigestAlgProperty ("DigestAlgorithm");
312 : 2250 : const OUString sDerivedKeySizeProperty ("DerivedKeySize");
313 : :
314 [ + - ]: 2250 : uno::Sequence < PropertyValue > aPropSet (PKG_SIZE_NOENCR_MNFST);
315 : :
316 : : OSL_ENSURE( ( rInfo.bFolder && rInfo.pFolder ) || ( !rInfo.bFolder && rInfo.pStream ), "A valid child object is expected!" );
317 [ + + ]: 2250 : if ( rInfo.bFolder )
318 : : {
319 : 912 : OUString sTempName = rPath + rShortName + "/";
320 : :
321 [ + + ]: 912 : if ( !rInfo.pFolder->GetMediaType().isEmpty() )
322 : : {
323 [ + - ]: 40 : aPropSet[PKG_MNFST_MEDIATYPE].Name = sMediaTypeProperty;
324 [ + - ][ + - ]: 40 : aPropSet[PKG_MNFST_MEDIATYPE].Value <<= rInfo.pFolder->GetMediaType();
325 [ + - ]: 40 : aPropSet[PKG_MNFST_VERSION].Name = sVersionProperty;
326 [ + - ][ + - ]: 40 : aPropSet[PKG_MNFST_VERSION].Value <<= rInfo.pFolder->GetVersion();
327 [ + - ]: 40 : aPropSet[PKG_MNFST_FULLPATH].Name = sFullPathProperty;
328 [ + - ][ + - ]: 40 : aPropSet[PKG_MNFST_FULLPATH].Value <<= sTempName;
329 : : }
330 : : else
331 [ + - ]: 872 : aPropSet.realloc( 0 );
332 : :
333 [ + - ]: 912 : rInfo.pFolder->saveContents( sTempName, rManList, rZipOut, rEncryptionKey, rRandomPool);
334 : : }
335 : : else
336 : : {
337 : : // if pTempEntry is necessary, it will be released and passed to the ZipOutputStream
338 : : // and be deleted in the ZipOutputStream destructor
339 [ + - ]: 1338 : auto_ptr < ZipEntry > pAutoTempEntry ( new ZipEntry );
340 : 1338 : ZipEntry* pTempEntry = pAutoTempEntry.get();
341 : :
342 : : // In case the entry we are reading is also the entry we are writing, we will
343 : : // store the ZipEntry data in pTempEntry
344 : :
345 : 1338 : ZipPackageFolder::copyZipEntry ( *pTempEntry, rInfo.pStream->aEntry );
346 : 1338 : pTempEntry->sPath = rPath + rShortName;
347 [ + - ]: 1338 : pTempEntry->nPathLen = (sal_Int16)( OUStringToOString( pTempEntry->sPath, RTL_TEXTENCODING_UTF8 ).getLength() );
348 : :
349 [ + - ][ - + ]: 1338 : sal_Bool bToBeEncrypted = rInfo.pStream->IsToBeEncrypted() && (rEncryptionKey.getLength() || rInfo.pStream->HasOwnKey());
[ + + ]
350 [ + - ]: 1338 : sal_Bool bToBeCompressed = bToBeEncrypted ? sal_True : rInfo.pStream->IsToBeCompressed();
351 : :
352 [ + - ]: 1338 : aPropSet[PKG_MNFST_MEDIATYPE].Name = sMediaTypeProperty;
353 [ + - ][ + - ]: 1338 : aPropSet[PKG_MNFST_MEDIATYPE].Value <<= rInfo.pStream->GetMediaType( );
354 [ + - ]: 1338 : aPropSet[PKG_MNFST_VERSION].Name = sVersionProperty;
355 [ + - ][ + - ]: 1338 : aPropSet[PKG_MNFST_VERSION].Value <<= OUString(); // no version is stored for streams currently
356 [ + - ]: 1338 : aPropSet[PKG_MNFST_FULLPATH].Name = sFullPathProperty;
357 [ + - ][ + - ]: 1338 : aPropSet[PKG_MNFST_FULLPATH].Value <<= pTempEntry->sPath;
358 : :
359 : :
360 : : OSL_ENSURE( rInfo.pStream->GetStreamMode() != PACKAGE_STREAM_NOTSET, "Unacceptable ZipPackageStream mode!" );
361 : :
362 : 1338 : sal_Bool bRawStream = sal_False;
363 [ + + ]: 1338 : if ( rInfo.pStream->GetStreamMode() == PACKAGE_STREAM_DETECT )
364 [ + - ]: 62 : bRawStream = rInfo.pStream->ParsePackageRawStream();
365 [ - + ]: 1276 : else if ( rInfo.pStream->GetStreamMode() == PACKAGE_STREAM_RAW )
366 : 0 : bRawStream = sal_True;
367 : :
368 : 1338 : sal_Bool bTransportOwnEncrStreamAsRaw = sal_False;
369 : : // During the storing the original size of the stream can be changed
370 : : // TODO/LATER: get rid of this hack
371 [ - + ]: 1338 : sal_Int32 nOwnStreamOrigSize = bRawStream ? rInfo.pStream->GetMagicalHackSize() : rInfo.pStream->getSize();
372 : :
373 : 1338 : sal_Bool bUseNonSeekableAccess = sal_False;
374 : 1338 : uno::Reference < XInputStream > xStream;
375 [ + - ][ + - ]: 1338 : if ( !rInfo.pStream->IsPackageMember() && !bRawStream && !bToBeEncrypted && bToBeCompressed )
[ + + ][ + + ]
[ + + ]
376 : : {
377 : : // the stream is not a package member, not a raw stream,
378 : : // it should not be encrypted and it should be compressed,
379 : : // in this case nonseekable access can be used
380 : :
381 [ + - ][ + - ]: 1106 : xStream = rInfo.pStream->GetOwnStreamNoWrap();
382 [ + - ]: 1106 : uno::Reference < XSeekable > xSeek ( xStream, uno::UNO_QUERY );
383 : :
384 [ + - ][ - + ]: 1106 : bUseNonSeekableAccess = ( xStream.is() && !xSeek.is() );
385 : : }
386 : :
387 [ + - ]: 1338 : if ( !bUseNonSeekableAccess )
388 : : {
389 [ + - ][ + - ]: 1338 : xStream = rInfo.pStream->getRawData();
[ # # ]
390 : :
391 [ - + ]: 1338 : if ( !xStream.is() )
392 : : {
393 : : OSL_FAIL( "ZipPackageStream didn't have a stream associated with it, skipping!" );
394 : 0 : bSuccess = false;
395 : 0 : return bSuccess;
396 : : }
397 : :
398 [ + - ]: 1338 : uno::Reference < XSeekable > xSeek ( xStream, uno::UNO_QUERY );
399 : : try
400 : : {
401 [ + + ]: 1338 : if ( xSeek.is() )
402 : : {
403 : : // If the stream is a raw one, then we should be positioned
404 : : // at the beginning of the actual data
405 [ + + ][ - + ]: 1182 : if ( !bToBeCompressed || bRawStream )
406 : : {
407 : : // The raw stream can neither be encrypted nor connected
408 : : OSL_ENSURE( !bRawStream || !(bToBeCompressed || bToBeEncrypted), "The stream is already encrypted!\n" );
409 [ + - ][ - + ]: 76 : xSeek->seek ( bRawStream ? rInfo.pStream->GetMagicalHackPos() : 0 );
[ + - ]
410 [ + - ]: 76 : ImplSetStoredData ( *pTempEntry, xStream );
411 : :
412 : : // TODO/LATER: Get rid of hacks related to switching of Flag Method and Size properties!
413 : : }
414 [ - + ]: 1106 : else if ( bToBeEncrypted )
415 : : {
416 : : // this is the correct original size
417 [ # # ][ # # ]: 0 : pTempEntry->nSize = static_cast < sal_Int32 > ( xSeek->getLength() );
418 : 0 : nOwnStreamOrigSize = pTempEntry->nSize;
419 : : }
420 : :
421 [ + - ][ + - ]: 1182 : xSeek->seek ( 0 );
422 : : }
423 : : else
424 : : {
425 : : // Okay, we don't have an xSeekable stream. This is possibly bad.
426 : : // check if it's one of our own streams, if it is then we know that
427 : : // each time we ask for it we'll get a new stream that will be
428 : : // at position zero...otherwise, assert and skip this stream...
429 [ + - ]: 156 : if ( rInfo.pStream->IsPackageMember() )
430 : : {
431 : : // if the password has been changed than the stream should not be package member any more
432 [ - + ][ # # ]: 156 : if ( rInfo.pStream->IsEncrypted() && rInfo.pStream->IsToBeEncrypted() )
[ - + ]
433 : : {
434 : : // Should be handled close to the raw stream handling
435 : 0 : bTransportOwnEncrStreamAsRaw = sal_True;
436 : 0 : pTempEntry->nMethod = STORED;
437 : :
438 : : // TODO/LATER: get rid of this situation
439 : : // this size should be different from the one that will be stored in manifest.xml
440 : : // it is used in storing algorithms and after storing the correct size will be set
441 : 0 : pTempEntry->nSize = pTempEntry->nCompressedSize;
442 : : }
443 : : }
444 : : else
445 : : {
446 : 0 : bSuccess = false;
447 : 0 : return bSuccess;
448 : : }
449 : : }
450 : : }
451 [ # # ]: 0 : catch ( uno::Exception& )
452 : : {
453 : 0 : bSuccess = false;
454 : 0 : return bSuccess;
455 : : }
456 : :
457 [ + - ][ + - ]: 1338 : if ( bToBeEncrypted || bRawStream || bTransportOwnEncrStreamAsRaw )
[ - + ]
458 : : {
459 [ # # ][ # # ]: 0 : if ( bToBeEncrypted && !bTransportOwnEncrStreamAsRaw )
460 : : {
461 [ # # ][ # # ]: 0 : uno::Sequence < sal_Int8 > aSalt( 16 ), aVector( rInfo.pStream->GetBlockSize() );
[ # # ]
462 [ # # ]: 0 : rtl_random_getBytes ( rRandomPool, aSalt.getArray(), 16 );
463 [ # # ]: 0 : rtl_random_getBytes ( rRandomPool, aVector.getArray(), aVector.getLength() );
464 : 0 : sal_Int32 nIterationCount = 1024;
465 : :
466 [ # # ]: 0 : if ( !rInfo.pStream->HasOwnKey() )
467 [ # # ]: 0 : rInfo.pStream->setKey ( rEncryptionKey );
468 : :
469 [ # # ]: 0 : rInfo.pStream->setInitialisationVector ( aVector );
470 [ # # ]: 0 : rInfo.pStream->setSalt ( aSalt );
471 [ # # ][ # # ]: 0 : rInfo.pStream->setIterationCount ( nIterationCount );
[ # # ]
472 : : }
473 : :
474 : : // last property is digest, which is inserted later if we didn't have
475 : : // a magic header
476 [ # # ]: 0 : aPropSet.realloc(PKG_SIZE_ENCR_MNFST);
477 : :
478 [ # # ]: 0 : aPropSet[PKG_MNFST_INIVECTOR].Name = sInitialisationVectorProperty;
479 [ # # ][ # # ]: 0 : aPropSet[PKG_MNFST_INIVECTOR].Value <<= rInfo.pStream->getInitialisationVector();
[ # # ][ # # ]
480 [ # # ]: 0 : aPropSet[PKG_MNFST_SALT].Name = sSaltProperty;
481 [ # # ][ # # ]: 0 : aPropSet[PKG_MNFST_SALT].Value <<= rInfo.pStream->getSalt();
[ # # ][ # # ]
482 [ # # ]: 0 : aPropSet[PKG_MNFST_ITERATION].Name = sIterationCountProperty;
483 [ # # ][ # # ]: 0 : aPropSet[PKG_MNFST_ITERATION].Value <<= rInfo.pStream->getIterationCount ();
[ # # ]
484 : :
485 : : // Need to store the uncompressed size in the manifest
486 : : OSL_ENSURE( nOwnStreamOrigSize >= 0, "The stream size was not correctly initialized!\n" );
487 [ # # ]: 0 : aPropSet[PKG_MNFST_UCOMPSIZE].Name = sSizeProperty;
488 [ # # ][ # # ]: 0 : aPropSet[PKG_MNFST_UCOMPSIZE].Value <<= nOwnStreamOrigSize;
489 : :
490 [ # # ][ # # ]: 0 : if ( bRawStream || bTransportOwnEncrStreamAsRaw )
491 : : {
492 [ # # ]: 0 : ::rtl::Reference< EncryptionData > xEncData = rInfo.pStream->GetEncryptionData();
493 [ # # ]: 0 : if ( !xEncData.is() )
494 [ # # ]: 0 : throw uno::RuntimeException();
495 : :
496 [ # # ]: 0 : aPropSet[PKG_MNFST_DIGEST].Name = sDigestProperty;
497 [ # # ][ # # ]: 0 : aPropSet[PKG_MNFST_DIGEST].Value <<= rInfo.pStream->getDigest();
[ # # ][ # # ]
498 [ # # ]: 0 : aPropSet[PKG_MNFST_ENCALG].Name = sEncryptionAlgProperty;
499 [ # # ][ # # ]: 0 : aPropSet[PKG_MNFST_ENCALG].Value <<= xEncData->m_nEncAlg;
500 [ # # ]: 0 : aPropSet[PKG_MNFST_STARTALG].Name = sStartKeyAlgProperty;
501 [ # # ][ # # ]: 0 : aPropSet[PKG_MNFST_STARTALG].Value <<= xEncData->m_nStartKeyGenID;
502 [ # # ]: 0 : aPropSet[PKG_MNFST_DIGESTALG].Name = sDigestAlgProperty;
503 [ # # ][ # # ]: 0 : aPropSet[PKG_MNFST_DIGESTALG].Value <<= xEncData->m_nCheckAlg;
504 [ # # ]: 0 : aPropSet[PKG_MNFST_DERKEYSIZE].Name = sDerivedKeySizeProperty;
505 [ # # ][ # # ]: 1338 : aPropSet[PKG_MNFST_DERKEYSIZE].Value <<= xEncData->m_nDerivedKeySize;
506 : : }
507 [ + - ]: 1338 : }
508 : : }
509 : :
510 : : // If the entry is already stored in the zip file in the format we
511 : : // want for this write...copy it raw
512 [ + - ][ + - ]: 2676 : if ( !bUseNonSeekableAccess
[ + - + + ]
[ + - ][ + - ]
[ - + ][ # # ]
[ # # ][ + + ]
513 : : && ( bRawStream || bTransportOwnEncrStreamAsRaw
514 : 1338 : || ( rInfo.pStream->IsPackageMember() && !bToBeEncrypted
515 : : && ( ( rInfo.pStream->aEntry.nMethod == DEFLATED && bToBeCompressed )
516 : : || ( rInfo.pStream->aEntry.nMethod == STORED && !bToBeCompressed ) ) ) ) )
517 : : {
518 : : // If it's a PackageMember, then it's an unbuffered stream and we need
519 : : // to get a new version of it as we can't seek backwards.
520 [ + - ]: 156 : if ( rInfo.pStream->IsPackageMember() )
521 : : {
522 [ + - ][ + - ]: 156 : xStream = rInfo.pStream->getRawData();
523 [ - + ]: 156 : if ( !xStream.is() )
524 : : {
525 : : // Make sure that we actually _got_ a new one !
526 : 0 : bSuccess = false;
527 : 0 : return bSuccess;
528 : : }
529 : : }
530 : :
531 : : try
532 : : {
533 [ - + ]: 156 : if ( bRawStream )
534 [ # # ][ # # ]: 0 : xStream->skipBytes( rInfo.pStream->GetMagicalHackPos() );
535 : :
536 [ + - ]: 156 : rZipOut.putNextEntry ( *pTempEntry, rInfo.pStream, sal_False );
537 : : // the entry is provided to the ZipOutputStream that will delete it
538 : 156 : pAutoTempEntry.release();
539 : :
540 [ + - ]: 156 : uno::Sequence < sal_Int8 > aSeq ( n_ConstBufferSize );
541 : : sal_Int32 nLength;
542 : :
543 [ - + ]: 156 : do
544 : : {
545 [ + - ][ + - ]: 156 : nLength = xStream->readBytes( aSeq, n_ConstBufferSize );
546 [ + - ]: 156 : rZipOut.rawWrite(aSeq, 0, nLength);
547 : : }
548 : : while ( nLength == n_ConstBufferSize );
549 : :
550 [ + - ][ + - ]: 156 : rZipOut.rawCloseEntry();
[ # # # ]
551 : : }
552 [ # # ]: 0 : catch ( ZipException& )
553 : : {
554 : 0 : bSuccess = false;
555 : : }
556 [ # # ]: 0 : catch ( IOException& )
557 : : {
558 : 0 : bSuccess = false;
559 : : }
560 : : }
561 : : else
562 : : {
563 : : // This stream is defenitly not a raw stream
564 : :
565 : : // If nonseekable access is used the stream should be at the beginning and
566 : : // is useless after the storing. Thus if the storing fails the package should
567 : : // be thrown away ( as actually it is done currently )!
568 : : // To allow to reuse the package after the error, the optimization must be removed!
569 : :
570 : : // If it's a PackageMember, then our previous reference held a 'raw' stream
571 : : // so we need to re-get it, unencrypted, uncompressed and positioned at the
572 : : // beginning of the stream
573 [ - + ]: 1182 : if ( rInfo.pStream->IsPackageMember() )
574 : : {
575 [ # # ][ # # ]: 0 : xStream = rInfo.pStream->getInputStream();
576 [ # # ]: 0 : if ( !xStream.is() )
577 : : {
578 : : // Make sure that we actually _got_ a new one !
579 : 0 : bSuccess = false;
580 : 0 : return bSuccess;
581 : : }
582 : : }
583 : :
584 [ + + ]: 1182 : if ( bToBeCompressed )
585 : : {
586 : 1106 : pTempEntry->nMethod = DEFLATED;
587 : 1106 : pTempEntry->nCrc = pTempEntry->nCompressedSize = pTempEntry->nSize = -1;
588 : : }
589 : :
590 : : try
591 : : {
592 [ + - ]: 1182 : rZipOut.putNextEntry ( *pTempEntry, rInfo.pStream, bToBeEncrypted);
593 : : // the entry is provided to the ZipOutputStream that will delete it
594 : 1182 : pAutoTempEntry.release();
595 : :
596 : : sal_Int32 nLength;
597 [ + - ]: 1182 : uno::Sequence < sal_Int8 > aSeq (n_ConstBufferSize);
598 [ + + ]: 1206 : do
599 : : {
600 [ + - ][ + - ]: 1206 : nLength = xStream->readBytes(aSeq, n_ConstBufferSize);
601 [ + - ]: 1206 : rZipOut.write(aSeq, 0, nLength);
602 : : }
603 : : while ( nLength == n_ConstBufferSize );
604 : :
605 [ + - ][ + - ]: 1182 : rZipOut.closeEntry();
[ # # # ]
606 : : }
607 [ # # ]: 0 : catch ( ZipException& )
608 : : {
609 : 0 : bSuccess = false;
610 : : }
611 [ # # ]: 0 : catch ( IOException& )
612 : : {
613 : 0 : bSuccess = false;
614 : : }
615 : :
616 [ - + ]: 1182 : if ( bToBeEncrypted )
617 : : {
618 [ # # ]: 0 : ::rtl::Reference< EncryptionData > xEncData = rInfo.pStream->GetEncryptionData();
619 [ # # ]: 0 : if ( !xEncData.is() )
620 [ # # ]: 0 : throw uno::RuntimeException();
621 : :
622 [ # # ]: 0 : aPropSet[PKG_MNFST_DIGEST].Name = sDigestProperty;
623 [ # # ][ # # ]: 0 : aPropSet[PKG_MNFST_DIGEST].Value <<= rInfo.pStream->getDigest();
[ # # ][ # # ]
624 [ # # ]: 0 : aPropSet[PKG_MNFST_ENCALG].Name = sEncryptionAlgProperty;
625 [ # # ][ # # ]: 0 : aPropSet[PKG_MNFST_ENCALG].Value <<= xEncData->m_nEncAlg;
626 [ # # ]: 0 : aPropSet[PKG_MNFST_STARTALG].Name = sStartKeyAlgProperty;
627 [ # # ][ # # ]: 0 : aPropSet[PKG_MNFST_STARTALG].Value <<= xEncData->m_nStartKeyGenID;
628 [ # # ]: 0 : aPropSet[PKG_MNFST_DIGESTALG].Name = sDigestAlgProperty;
629 [ # # ][ # # ]: 0 : aPropSet[PKG_MNFST_DIGESTALG].Value <<= xEncData->m_nCheckAlg;
630 [ # # ]: 0 : aPropSet[PKG_MNFST_DERKEYSIZE].Name = sDerivedKeySizeProperty;
631 [ # # ][ # # ]: 0 : aPropSet[PKG_MNFST_DERKEYSIZE].Value <<= xEncData->m_nDerivedKeySize;
632 : :
633 : 0 : rInfo.pStream->SetIsEncrypted ( sal_True );
634 : : }
635 : : }
636 : :
637 [ + - ]: 1338 : if( bSuccess )
638 : : {
639 [ + + ]: 1338 : if ( !rInfo.pStream->IsPackageMember() )
640 : : {
641 [ + - ]: 1182 : rInfo.pStream->CloseOwnStreamIfAny();
642 [ + - ]: 1182 : rInfo.pStream->SetPackageMember ( sal_True );
643 : : }
644 : :
645 [ - + ]: 1338 : if ( bRawStream )
646 : : {
647 : : // the raw stream was integrated and now behaves
648 : : // as usual encrypted stream
649 [ # # ]: 0 : rInfo.pStream->SetToBeEncrypted( sal_True );
650 : : }
651 : :
652 : : // Then copy it back afterwards...
653 : 1338 : ZipPackageFolder::copyZipEntry ( rInfo.pStream->aEntry, *pTempEntry );
654 : :
655 : : // Remove hacky bit from entry flags
656 [ - + ]: 1338 : if ( rInfo.pStream->aEntry.nFlag & ( 1 << 4 ) )
657 : : {
658 : 0 : rInfo.pStream->aEntry.nFlag &= ~( 1 << 4 );
659 : 0 : rInfo.pStream->aEntry.nMethod = STORED;
660 : : }
661 : :
662 : : // TODO/LATER: get rid of this hack ( the encrypted stream size property is changed during saving )
663 [ - + ]: 1338 : if ( rInfo.pStream->IsEncrypted() )
664 [ # # ]: 0 : rInfo.pStream->setSize( nOwnStreamOrigSize );
665 : :
666 : 1338 : rInfo.pStream->aEntry.nOffset *= -1;
667 [ - + ][ + - ]: 1338 : }
668 : : }
669 : :
670 : : // folder can have a mediatype only in package format
671 [ + + ][ + + ]: 2250 : if ( aPropSet.getLength()
[ + + ][ + - ]
[ + + ]
672 : 459 : && ( m_nFormat == embed::StorageFormats::PACKAGE || ( m_nFormat == embed::StorageFormats::OFOPXML && !rInfo.bFolder ) ) )
673 [ + - ]: 1254 : rManList.push_back( aPropSet );
674 : :
675 [ + - ]: 2250 : return bSuccess;
676 : : }
677 : :
678 : 1374 : void ZipPackageFolder::saveContents( OUString &rPath, std::vector < uno::Sequence < PropertyValue > > &rManList, ZipOutputStream & rZipOut, const uno::Sequence < sal_Int8 >& rEncryptionKey, rtlRandomPool &rRandomPool )
679 : : throw( uno::RuntimeException )
680 : : {
681 : 1374 : bool bWritingFailed = false;
682 : :
683 [ + - ][ + - ]: 1374 : if ( maContents.begin() == maContents.end() && !rPath.isEmpty() && m_nFormat != embed::StorageFormats::OFOPXML )
[ + + ][ + - ]
[ + - ][ + - ]
[ + - ][ + +
# # # # #
# # ]
684 : : {
685 : : // it is an empty subfolder, use workaround to store it
686 [ + - ]: 330 : ZipEntry* pTempEntry = new ZipEntry();
687 : 330 : ZipPackageFolder::copyZipEntry ( *pTempEntry, aEntry );
688 [ + - ]: 330 : pTempEntry->nPathLen = (sal_Int16)( OUStringToOString( rPath, RTL_TEXTENCODING_UTF8 ).getLength() );
689 : 330 : pTempEntry->nExtraLen = -1;
690 : 330 : pTempEntry->sPath = rPath;
691 : :
692 : : try
693 : : {
694 [ + - ]: 330 : rZipOut.putNextEntry( *pTempEntry, NULL, sal_False );
695 [ + - ]: 330 : rZipOut.rawCloseEntry();
696 : : }
697 [ # # ]: 0 : catch ( ZipException& )
698 : : {
699 : 0 : bWritingFailed = true;
700 : : }
701 [ # # ]: 0 : catch ( IOException& )
702 : : {
703 : 0 : bWritingFailed = true;
704 : : }
705 : : }
706 : :
707 : 1374 : bool bMimeTypeStreamStored = false;
708 : 1374 : OUString aMimeTypeStreamName("mimetype");
709 [ + + ][ + + ]: 1374 : if ( m_nFormat == embed::StorageFormats::ZIP && rPath.isEmpty() )
[ + + ]
710 : : {
711 : : // let the "mimtype" stream in root folder be stored as the first stream if it is zip format
712 [ + - ]: 124 : ContentHash::iterator aIter = maContents.find ( aMimeTypeStreamName );
713 [ + - ][ - + ]: 124 : if ( aIter != maContents.end() && !(*aIter).second->bFolder )
[ # # ][ # # ]
[ + - ]
[ - + # # ]
714 : : {
715 : 0 : bMimeTypeStreamStored = true;
716 [ # # ][ # # ]: 124 : bWritingFailed = !saveChild( (*aIter).first, *(*aIter).second, rPath, rManList, rZipOut, rEncryptionKey, rRandomPool );
[ # # ]
717 : : }
718 : : }
719 : :
720 [ + - ][ + - ]: 3624 : for ( ContentHash::const_iterator aCI = maContents.begin(), aEnd = maContents.end();
[ + + ]
721 : : aCI != aEnd;
722 : : ++aCI)
723 : : {
724 [ + - ]: 2250 : const OUString &rShortName = (*aCI).first;
725 [ + - ]: 2250 : const ContentInfo &rInfo = *(*aCI).second;
726 : :
727 [ # # ][ + - ]: 2250 : if ( !bMimeTypeStreamStored || !rShortName.equals( aMimeTypeStreamName ) )
[ - + ]
728 [ + - ]: 2250 : bWritingFailed = !saveChild( rShortName, rInfo, rPath, rManList, rZipOut, rEncryptionKey, rRandomPool );
729 : : }
730 : :
731 [ - + ]: 1374 : if( bWritingFailed )
732 [ # # ]: 1374 : throw uno::RuntimeException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
733 : 1374 : }
734 : :
735 : 10014 : void ZipPackageFolder::releaseUpwardRef( void )
736 : : {
737 : : // Now it is possible that a package folder is disconnected from the package before removing of the folder.
738 : : // Such a scenario is used in storage implementation. When a new version of a folder is provided the old
739 : : // one is retrieved, removed from the package but preserved for the error handling.
740 : : // In this scenario the referencing to the parent is not really useful, since it requires disposing.
741 : :
742 : : // Actually there is no need in having a reference to the parent, it even make things more complicated and
743 : : // requires disposing mechanics. Using of a simple pointer seems to be easier solution and also a safe enough.
744 : :
745 : 10014 : clearParent();
746 : :
747 : : #if 0
748 : : for ( ContentHash::const_iterator aCI = maContents.begin();
749 : : aCI!=maContents.end();
750 : : aCI++)
751 : : {
752 : : ContentInfo &rInfo = * (*aCI).second;
753 : : if ( rInfo.bFolder )// && ! rInfo.pFolder->HasReleased () )
754 : : rInfo.pFolder->releaseUpwardRef();
755 : : else //if ( !rInfo.bFolder && !rInfo.pStream->HasReleased() )
756 : : rInfo.pStream->clearParent();
757 : : }
758 : : clearParent();
759 : :
760 : : OSL_ENSURE ( m_refCount == 1, "Ref-count is not 1!" );
761 : : #endif
762 : 10014 : }
763 : :
764 : 6264 : sal_Int64 SAL_CALL ZipPackageFolder::getSomething( const uno::Sequence< sal_Int8 >& aIdentifier )
765 : : throw(uno::RuntimeException)
766 : : {
767 : 6264 : sal_Int64 nMe = 0;
768 [ + - + - ]: 12528 : if ( aIdentifier.getLength() == 16 &&
[ + - ]
769 : 6264 : 0 == memcmp(static_getImplementationId().getConstArray(), aIdentifier.getConstArray(), 16 ) )
770 : 6264 : nMe = reinterpret_cast < sal_Int64 > ( this );
771 : 6264 : return nMe;
772 : : }
773 : 3518 : void SAL_CALL ZipPackageFolder::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
774 : : throw(UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, uno::RuntimeException)
775 : : {
776 [ + + ]: 3518 : if ( aPropertyName == "MediaType" )
777 : : {
778 : : // TODO/LATER: activate when zip ucp is ready
779 : : // if ( m_nFormat != embed::StorageFormats::PACKAGE )
780 : : // throw UnknownPropertyException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
781 : :
782 : 1759 : aValue >>= sMediaType;
783 : : }
784 [ + - ]: 1759 : else if ( aPropertyName == "Version" )
785 : 1759 : aValue >>= m_sVersion;
786 [ # # ]: 0 : else if ( aPropertyName == "Size" )
787 : 0 : aValue >>= aEntry.nSize;
788 : : else
789 [ # # ]: 0 : throw UnknownPropertyException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
790 : 3518 : }
791 : 49366 : uno::Any SAL_CALL ZipPackageFolder::getPropertyValue( const OUString& PropertyName )
792 : : throw(UnknownPropertyException, WrappedTargetException, uno::RuntimeException)
793 : : {
794 [ + + ]: 49366 : if ( PropertyName == "MediaType" )
795 : : {
796 : : // TODO/LATER: activate when zip ucp is ready
797 : : // if ( m_nFormat != embed::StorageFormats::PACKAGE )
798 : : // throw UnknownPropertyException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
799 : :
800 : 24681 : return uno::makeAny ( sMediaType );
801 : : }
802 [ + - ]: 24685 : else if ( PropertyName == "Version" )
803 : 24685 : return uno::makeAny( m_sVersion );
804 [ # # ]: 0 : else if ( PropertyName == "Size" )
805 : 0 : return uno::makeAny ( aEntry.nSize );
806 : : else
807 [ # # ]: 49366 : throw UnknownPropertyException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
808 : : }
809 : :
810 : 26519 : void ZipPackageFolder::doInsertByName ( ZipPackageEntry *pEntry, sal_Bool bSetParent )
811 : : throw(IllegalArgumentException, ElementExistException, WrappedTargetException, uno::RuntimeException)
812 : : {
813 : : try
814 : : {
815 [ + + ]: 26519 : if ( pEntry->IsFolder() )
816 [ + - ][ + - ]: 10356 : maContents[pEntry->getName()] = new ContentInfo ( static_cast < ZipPackageFolder *> ( pEntry ) );
[ + - ][ + - ]
817 : : else
818 [ + - ][ + - ]: 16163 : maContents[pEntry->getName()] = new ContentInfo ( static_cast < ZipPackageStream *> ( pEntry ) );
[ + - ][ + - ]
819 : : }
820 [ # # ]: 0 : catch(const uno::Exception& rEx)
821 : : {
822 : : (void)rEx;
823 : 0 : throw;
824 : : }
825 [ + + ]: 26519 : if ( bSetParent )
826 [ + - ]: 4033 : pEntry->setParent ( *this );
827 : 26519 : }
828 : 0 : OUString ZipPackageFolder::getImplementationName()
829 : : throw (uno::RuntimeException)
830 : : {
831 : 0 : return OUString("ZipPackageFolder");
832 : : }
833 : :
834 : 0 : uno::Sequence< OUString > ZipPackageFolder::getSupportedServiceNames()
835 : : throw (uno::RuntimeException)
836 : : {
837 : 0 : uno::Sequence< OUString > aNames(1);
838 [ # # ]: 0 : aNames[0] = "com.sun.star.packages.PackageFolder";
839 : 0 : return aNames;
840 : : }
841 : 0 : sal_Bool SAL_CALL ZipPackageFolder::supportsService( OUString const & rServiceName )
842 : : throw (uno::RuntimeException)
843 : : {
844 [ # # ]: 0 : return rServiceName == getSupportedServiceNames()[0];
845 : : }
846 : :
847 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|