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 .
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 <cppuhelper/supportsservice.hxx>
31 #include <cppuhelper/typeprovider.hxx>
32 #include <osl/diagnose.h>
34 #include <rtl/digest.h>
35 #include <ContentInfo.hxx>
36 #include <com/sun/star/beans/PropertyValue.hpp>
37 #include <EncryptedDataHeader.hxx>
38 #include <rtl/instance.hxx>
39 #include <boost/scoped_ptr.hpp>
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
;
51 #if OSL_DEBUG_LEVEL > 0
52 #define THROW_WHERE SAL_WHERE
54 #define THROW_WHERE ""
57 namespace { struct lcl_CachedImplId
: public rtl::Static
< cppu::OImplementationId
, lcl_CachedImplId
> {}; }
59 ZipPackageFolder::ZipPackageFolder( const css::uno::Reference
< css::uno::XComponentContext
>& xContext
,
61 bool bAllowRemoveOnInsert
)
63 m_xContext
= xContext
;
65 mbAllowRemoveOnInsert
= bAllowRemoveOnInsert
;
69 aEntry
.nMethod
= STORED
;
72 aEntry
.nCompressedSize
= 0;
77 ZipPackageFolder::~ZipPackageFolder()
81 bool ZipPackageFolder::LookForUnexpectedODF12Streams( const OUString
& aPath
)
83 bool bHasUnexpected
= false;
85 for ( ContentHash::const_iterator aCI
= maContents
.begin(), aEnd
= maContents
.end();
86 !bHasUnexpected
&& aCI
!= aEnd
;
89 const OUString
&rShortName
= (*aCI
).first
;
90 const ContentInfo
&rInfo
= *(*aCI
).second
;
94 if ( aPath
== "META-INF/" )
96 // META-INF is not allowed to contain subfolders
97 bHasUnexpected
= true;
101 OUString sOwnPath
= aPath
+ rShortName
+ "/";
102 bHasUnexpected
= rInfo
.pFolder
->LookForUnexpectedODF12Streams( sOwnPath
);
107 if ( aPath
== "META-INF/" )
109 if ( rShortName
!= "manifest.xml"
110 && rShortName
.indexOf( "signatures" ) == -1 )
112 // a stream from META-INF with unexpected name
113 bHasUnexpected
= true;
116 // streams from META-INF with expected names are allowed not to be registered in manifest.xml
118 else if ( !rInfo
.pStream
->IsFromManifest() )
120 // the stream is not in META-INF and is not registered in manifest.xml,
121 // check whether it is an internal part of the package format
122 if ( !aPath
.isEmpty() || rShortName
!= "mimetype" )
124 // if it is not "mimetype" from the root it is not a part of the package
125 bHasUnexpected
= true;
131 return bHasUnexpected
;
134 void ZipPackageFolder::setChildStreamsTypeByExtension( const beans::StringPair
& aPair
)
137 if ( aPair
.First
.toChar() == (sal_Unicode
)'.' )
140 aExt
= "." + aPair
.First
;
142 for ( ContentHash::const_iterator aCI
= maContents
.begin(), aEnd
= maContents
.end();
146 const OUString
&rShortName
= (*aCI
).first
;
147 const ContentInfo
&rInfo
= *(*aCI
).second
;
150 rInfo
.pFolder
->setChildStreamsTypeByExtension( aPair
);
153 sal_Int32 nPathLength
= rShortName
.getLength();
154 sal_Int32 nExtLength
= aExt
.getLength();
155 if ( nPathLength
>= nExtLength
&& rShortName
.match( aExt
, nPathLength
- nExtLength
) )
156 rInfo
.pStream
->SetMediaType( aPair
.Second
);
161 void ZipPackageFolder::copyZipEntry( ZipEntry
&rDest
, const ZipEntry
&rSource
)
163 rDest
.nVersion
= rSource
.nVersion
;
164 rDest
.nFlag
= rSource
.nFlag
;
165 rDest
.nMethod
= rSource
.nMethod
;
166 rDest
.nTime
= rSource
.nTime
;
167 rDest
.nCrc
= rSource
.nCrc
;
168 rDest
.nCompressedSize
= rSource
.nCompressedSize
;
169 rDest
.nSize
= rSource
.nSize
;
170 rDest
.nOffset
= rSource
.nOffset
;
171 rDest
.sPath
= rSource
.sPath
;
172 rDest
.nPathLen
= rSource
.nPathLen
;
173 rDest
.nExtraLen
= rSource
.nExtraLen
;
176 ::com::sun::star::uno::Sequence
< sal_Int8
> ZipPackageFolder::static_getImplementationId()
178 return lcl_CachedImplId::get().getImplementationId();
182 void SAL_CALL
ZipPackageFolder::insertByName( const OUString
& aName
, const uno::Any
& aElement
)
183 throw(IllegalArgumentException
, ElementExistException
, WrappedTargetException
, uno::RuntimeException
, std::exception
)
185 if (hasByName(aName
))
186 throw ElementExistException(THROW_WHERE
);
189 uno::Reference
< XUnoTunnel
> xRef
;
191 if ( ( aElement
>>= xRef
) )
194 ZipPackageEntry
*pEntry
;
195 if ( ( nTest
= xRef
->getSomething ( ZipPackageFolder::static_getImplementationId() ) ) != 0 )
197 ZipPackageFolder
*pFolder
= reinterpret_cast < ZipPackageFolder
* > ( nTest
);
198 pEntry
= static_cast < ZipPackageEntry
* > ( pFolder
);
200 else if ( ( nTest
= xRef
->getSomething ( ZipPackageStream::static_getImplementationId() ) ) != 0 )
202 ZipPackageStream
*pStream
= reinterpret_cast < ZipPackageStream
* > ( nTest
);
203 pEntry
= static_cast < ZipPackageEntry
* > ( pStream
);
206 throw IllegalArgumentException(THROW_WHERE
, uno::Reference
< uno::XInterface
>(), 0 );
208 if (pEntry
->getName() != aName
)
209 pEntry
->setName (aName
);
210 doInsertByName ( pEntry
, true );
213 throw IllegalArgumentException(THROW_WHERE
, uno::Reference
< uno::XInterface
>(), 0 );
216 void SAL_CALL
ZipPackageFolder::removeByName( const OUString
& Name
)
217 throw(NoSuchElementException
, WrappedTargetException
, uno::RuntimeException
, std::exception
)
219 ContentHash::iterator aIter
= maContents
.find ( Name
);
220 if ( aIter
== maContents
.end() )
221 throw NoSuchElementException(THROW_WHERE
);
222 maContents
.erase( aIter
);
224 // XEnumerationAccess
225 uno::Reference
< XEnumeration
> SAL_CALL
ZipPackageFolder::createEnumeration( )
226 throw(uno::RuntimeException
, std::exception
)
228 return uno::Reference
< XEnumeration
> (new ZipPackageFolderEnumeration(maContents
));
231 uno::Type SAL_CALL
ZipPackageFolder::getElementType( )
232 throw(uno::RuntimeException
, std::exception
)
234 return cppu::UnoType
<XUnoTunnel
>::get();
236 sal_Bool SAL_CALL
ZipPackageFolder::hasElements( )
237 throw(uno::RuntimeException
, std::exception
)
239 return maContents
.size() > 0;
242 ContentInfo
& ZipPackageFolder::doGetByName( const OUString
& aName
)
243 throw(NoSuchElementException
, WrappedTargetException
, uno::RuntimeException
)
245 ContentHash::iterator aIter
= maContents
.find ( aName
);
246 if ( aIter
== maContents
.end())
247 throw NoSuchElementException(THROW_WHERE
);
248 return *(*aIter
).second
;
250 uno::Any SAL_CALL
ZipPackageFolder::getByName( const OUString
& aName
)
251 throw(NoSuchElementException
, WrappedTargetException
, uno::RuntimeException
, std::exception
)
253 return uno::makeAny ( doGetByName ( aName
).xTunnel
);
255 uno::Sequence
< OUString
> SAL_CALL
ZipPackageFolder::getElementNames( )
256 throw(uno::RuntimeException
, std::exception
)
258 sal_uInt32 i
=0, nSize
= maContents
.size();
259 uno::Sequence
< OUString
> aSequence ( nSize
);
260 for ( ContentHash::const_iterator aIterator
= maContents
.begin(), aEnd
= maContents
.end();
263 aSequence
[i
] = (*aIterator
).first
;
266 sal_Bool SAL_CALL
ZipPackageFolder::hasByName( const OUString
& aName
)
267 throw(uno::RuntimeException
, std::exception
)
269 return maContents
.find ( aName
) != maContents
.end ();
272 void SAL_CALL
ZipPackageFolder::replaceByName( const OUString
& aName
, const uno::Any
& aElement
)
273 throw(IllegalArgumentException
, NoSuchElementException
, WrappedTargetException
, uno::RuntimeException
, std::exception
)
275 if ( hasByName( aName
) )
276 removeByName( aName
);
278 throw NoSuchElementException(THROW_WHERE
);
279 insertByName(aName
, aElement
);
282 bool ZipPackageFolder::saveChild(
283 const OUString
&rPath
,
284 std::vector
< uno::Sequence
< PropertyValue
> > &rManList
,
285 ZipOutputStream
& rZipOut
,
286 const uno::Sequence
< sal_Int8
>& rEncryptionKey
,
287 const rtlRandomPool
&rRandomPool
)
289 bool bSuccess
= true;
291 const OUString
sMediaTypeProperty ("MediaType");
292 const OUString
sVersionProperty ("Version");
293 const OUString
sFullPathProperty ("FullPath");
295 uno::Sequence
< PropertyValue
> aPropSet (PKG_SIZE_NOENCR_MNFST
);
296 OUString sTempName
= rPath
+ "/";
298 if ( !GetMediaType().isEmpty() )
300 aPropSet
[PKG_MNFST_MEDIATYPE
].Name
= sMediaTypeProperty
;
301 aPropSet
[PKG_MNFST_MEDIATYPE
].Value
<<= GetMediaType();
302 aPropSet
[PKG_MNFST_VERSION
].Name
= sVersionProperty
;
303 aPropSet
[PKG_MNFST_VERSION
].Value
<<= GetVersion();
304 aPropSet
[PKG_MNFST_FULLPATH
].Name
= sFullPathProperty
;
305 aPropSet
[PKG_MNFST_FULLPATH
].Value
<<= sTempName
;
308 aPropSet
.realloc( 0 );
310 saveContents( sTempName
, rManList
, rZipOut
, rEncryptionKey
, rRandomPool
);
312 // folder can have a mediatype only in package format
313 if ( aPropSet
.getLength() && ( m_nFormat
== embed::StorageFormats::PACKAGE
) )
314 rManList
.push_back( aPropSet
);
319 void ZipPackageFolder::saveContents(
320 const OUString
&rPath
,
321 std::vector
< uno::Sequence
< PropertyValue
> > &rManList
,
322 ZipOutputStream
& rZipOut
,
323 const uno::Sequence
< sal_Int8
>& rEncryptionKey
,
324 const rtlRandomPool
&rRandomPool
) const
325 throw( uno::RuntimeException
)
327 bool bWritingFailed
= false;
329 if ( maContents
.begin() == maContents
.end() && !rPath
.isEmpty() && m_nFormat
!= embed::StorageFormats::OFOPXML
)
331 // it is an empty subfolder, use workaround to store it
332 ZipEntry
* pTempEntry
= new ZipEntry();
333 ZipPackageFolder::copyZipEntry ( *pTempEntry
, aEntry
);
334 pTempEntry
->nPathLen
= (sal_Int16
)( OUStringToOString( rPath
, RTL_TEXTENCODING_UTF8
).getLength() );
335 pTempEntry
->nExtraLen
= -1;
336 pTempEntry
->sPath
= rPath
;
340 ZipOutputStream::setEntry(pTempEntry
);
341 rZipOut
.writeLOC(pTempEntry
);
342 rZipOut
.rawCloseEntry();
344 catch ( ZipException
& )
346 bWritingFailed
= true;
348 catch ( IOException
& )
350 bWritingFailed
= true;
354 bool bMimeTypeStreamStored
= false;
355 OUString
aMimeTypeStreamName("mimetype");
356 if ( m_nFormat
== embed::StorageFormats::ZIP
&& rPath
.isEmpty() )
358 // let the "mimetype" stream in root folder be stored as the first stream if it is zip format
359 ContentHash::const_iterator aIter
= maContents
.find ( aMimeTypeStreamName
);
360 if ( aIter
!= maContents
.end() && !(*aIter
).second
->bFolder
)
362 bMimeTypeStreamStored
= true;
363 bWritingFailed
= !aIter
->second
->pStream
->saveChild(
364 rPath
+ aIter
->first
, rManList
, rZipOut
, rEncryptionKey
, rRandomPool
);
368 for ( ContentHash::const_iterator aCI
= maContents
.begin(), aEnd
= maContents
.end();
372 const OUString
&rShortName
= (*aCI
).first
;
373 const ContentInfo
&rInfo
= *(*aCI
).second
;
375 if ( !bMimeTypeStreamStored
|| !rShortName
.equals( aMimeTypeStreamName
) )
379 bWritingFailed
= !rInfo
.pFolder
->saveChild(
380 rPath
+ rShortName
, rManList
, rZipOut
, rEncryptionKey
, rRandomPool
);
384 bWritingFailed
= !rInfo
.pStream
->saveChild(
385 rPath
+ rShortName
, rManList
, rZipOut
, rEncryptionKey
, rRandomPool
);
391 throw uno::RuntimeException(THROW_WHERE
);
394 sal_Int64 SAL_CALL
ZipPackageFolder::getSomething( const uno::Sequence
< sal_Int8
>& aIdentifier
)
395 throw(uno::RuntimeException
, std::exception
)
398 if ( aIdentifier
.getLength() == 16 &&
399 0 == memcmp(static_getImplementationId().getConstArray(), aIdentifier
.getConstArray(), 16 ) )
400 nMe
= reinterpret_cast < sal_Int64
> ( this );
403 void SAL_CALL
ZipPackageFolder::setPropertyValue( const OUString
& aPropertyName
, const uno::Any
& aValue
)
404 throw(UnknownPropertyException
, PropertyVetoException
, IllegalArgumentException
, WrappedTargetException
, uno::RuntimeException
, std::exception
)
406 if ( aPropertyName
== "MediaType" )
408 // TODO/LATER: activate when zip ucp is ready
409 // if ( m_nFormat != embed::StorageFormats::PACKAGE )
410 // throw UnknownPropertyException(THROW_WHERE );
412 aValue
>>= msMediaType
;
414 else if ( aPropertyName
== "Version" )
415 aValue
>>= m_sVersion
;
416 else if ( aPropertyName
== "Size" )
417 aValue
>>= aEntry
.nSize
;
419 throw UnknownPropertyException(THROW_WHERE
);
421 uno::Any SAL_CALL
ZipPackageFolder::getPropertyValue( const OUString
& PropertyName
)
422 throw(UnknownPropertyException
, WrappedTargetException
, uno::RuntimeException
, std::exception
)
424 if ( PropertyName
== "MediaType" )
426 // TODO/LATER: activate when zip ucp is ready
427 // if ( m_nFormat != embed::StorageFormats::PACKAGE )
428 // throw UnknownPropertyException(THROW_WHERE );
430 return uno::makeAny ( msMediaType
);
432 else if ( PropertyName
== "Version" )
433 return uno::makeAny( m_sVersion
);
434 else if ( PropertyName
== "Size" )
435 return uno::makeAny ( aEntry
.nSize
);
437 throw UnknownPropertyException(THROW_WHERE
);
440 void ZipPackageFolder::doInsertByName ( ZipPackageEntry
*pEntry
, bool bSetParent
)
441 throw(IllegalArgumentException
, ElementExistException
, WrappedTargetException
, uno::RuntimeException
)
445 if ( pEntry
->IsFolder() )
446 maContents
[pEntry
->getName()] = new ContentInfo ( static_cast < ZipPackageFolder
*> ( pEntry
) );
448 maContents
[pEntry
->getName()] = new ContentInfo ( static_cast < ZipPackageStream
*> ( pEntry
) );
450 catch(const uno::Exception
& rEx
)
456 pEntry
->setParent ( *this );
458 OUString
ZipPackageFolder::getImplementationName()
459 throw (uno::RuntimeException
, std::exception
)
461 return OUString("ZipPackageFolder");
464 uno::Sequence
< OUString
> ZipPackageFolder::getSupportedServiceNames()
465 throw (uno::RuntimeException
, std::exception
)
467 uno::Sequence
< OUString
> aNames(1);
468 aNames
[0] = "com.sun.star.packages.PackageFolder";
472 sal_Bool SAL_CALL
ZipPackageFolder::supportsService( OUString
const & rServiceName
)
473 throw (uno::RuntimeException
, std::exception
)
475 return cppu::supportsService(this, rServiceName
);
478 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */