Bump version to 5.0-14
[LibreOffice.git] / package / source / zippackage / ZipPackageFolder.cxx
blobcb72ed180f4a57cf2ed4aeccc5fb8fd7405ce03c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <string.h>
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>
33 #include <osl/time.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;
49 using namespace cppu;
51 #if OSL_DEBUG_LEVEL > 0
52 #define THROW_WHERE SAL_WHERE
53 #else
54 #define THROW_WHERE ""
55 #endif
57 namespace { struct lcl_CachedImplId : public rtl::Static< cppu::OImplementationId, lcl_CachedImplId > {}; }
59 ZipPackageFolder::ZipPackageFolder( const css::uno::Reference < css::uno::XComponentContext >& xContext,
60 sal_Int32 nFormat,
61 bool bAllowRemoveOnInsert )
63 m_xContext = xContext;
64 m_nFormat = nFormat;
65 mbAllowRemoveOnInsert = bAllowRemoveOnInsert;
66 SetFolder ( true );
67 aEntry.nVersion = -1;
68 aEntry.nFlag = 0;
69 aEntry.nMethod = STORED;
70 aEntry.nTime = -1;
71 aEntry.nCrc = 0;
72 aEntry.nCompressedSize = 0;
73 aEntry.nSize = 0;
74 aEntry.nOffset = -1;
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;
87 ++aCI)
89 const OUString &rShortName = (*aCI).first;
90 const ContentInfo &rInfo = *(*aCI).second;
92 if ( rInfo.bFolder )
94 if ( aPath == "META-INF/" )
96 // META-INF is not allowed to contain subfolders
97 bHasUnexpected = true;
99 else
101 OUString sOwnPath = aPath + rShortName + "/";
102 bHasUnexpected = rInfo.pFolder->LookForUnexpectedODF12Streams( sOwnPath );
105 else
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 )
136 OUString aExt;
137 if ( aPair.First.toChar() == (sal_Unicode)'.' )
138 aExt = aPair.First;
139 else
140 aExt = "." + aPair.First;
142 for ( ContentHash::const_iterator aCI = maContents.begin(), aEnd = maContents.end();
143 aCI != aEnd;
144 ++aCI)
146 const OUString &rShortName = (*aCI).first;
147 const ContentInfo &rInfo = *(*aCI).second;
149 if ( rInfo.bFolder )
150 rInfo.pFolder->setChildStreamsTypeByExtension( aPair );
151 else
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();
181 // XNameContainer
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 );
187 else
189 uno::Reference < XUnoTunnel > xRef;
190 aElement >>= xRef;
191 if ( ( aElement >>= xRef ) )
193 sal_Int64 nTest;
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 );
205 else
206 throw IllegalArgumentException(THROW_WHERE, uno::Reference< uno::XInterface >(), 0 );
208 if (pEntry->getName() != aName )
209 pEntry->setName (aName);
210 doInsertByName ( pEntry, true );
212 else
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));
230 // XElementAccess
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;
241 // XNameAccess
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();
261 aIterator != aEnd;
262 ++i, ++aIterator)
263 aSequence[i] = (*aIterator).first;
264 return aSequence;
266 sal_Bool SAL_CALL ZipPackageFolder::hasByName( const OUString& aName )
267 throw(uno::RuntimeException, std::exception)
269 return maContents.find ( aName ) != maContents.end ();
271 // XNameReplace
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 );
277 else
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;
307 else
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 );
316 return bSuccess;
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();
369 aCI != aEnd;
370 ++aCI)
372 const OUString &rShortName = (*aCI).first;
373 const ContentInfo &rInfo = *(*aCI).second;
375 if ( !bMimeTypeStreamStored || !rShortName.equals( aMimeTypeStreamName ) )
377 if (rInfo.bFolder)
379 bWritingFailed = !rInfo.pFolder->saveChild(
380 rPath + rShortName, rManList, rZipOut, rEncryptionKey, rRandomPool );
382 else
384 bWritingFailed = !rInfo.pStream->saveChild(
385 rPath + rShortName, rManList, rZipOut, rEncryptionKey, rRandomPool );
390 if( bWritingFailed )
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)
397 sal_Int64 nMe = 0;
398 if ( aIdentifier.getLength() == 16 &&
399 0 == memcmp(static_getImplementationId().getConstArray(), aIdentifier.getConstArray(), 16 ) )
400 nMe = reinterpret_cast < sal_Int64 > ( this );
401 return nMe;
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;
418 else
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 );
436 else
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 ) );
447 else
448 maContents[pEntry->getName()] = new ContentInfo ( static_cast < ZipPackageStream *> ( pEntry ) );
450 catch(const uno::Exception& rEx)
452 (void)rEx;
453 throw;
455 if ( bSetParent )
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";
469 return aNames;
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: */