Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / package / source / zippackage / ZipPackageFolder.cxx
blob8d9556069d95b25c829a12e64765f8e76359118b
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 <rtl/digest.h>
34 #include "ContentInfo.hxx"
35 #include <com/sun/star/beans/PropertyValue.hpp>
36 #include <EncryptedDataHeader.hxx>
37 #include <rtl/instance.hxx>
39 #include <o3tl/make_unique.hxx>
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 ZipContentInfo &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() == '.' )
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 ZipContentInfo &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 css::uno::Sequence < sal_Int8 > ZipPackageFolder::static_getImplementationId()
163 return lcl_CachedImplId::get().getImplementationId();
166 // XNameContainer
167 void SAL_CALL ZipPackageFolder::insertByName( const OUString& aName, const uno::Any& aElement )
169 if (hasByName(aName))
170 throw ElementExistException(THROW_WHERE );
172 uno::Reference < XUnoTunnel > xRef;
173 aElement >>= xRef;
174 if ( !(aElement >>= xRef) )
175 throw IllegalArgumentException(THROW_WHERE, uno::Reference< uno::XInterface >(), 0 );
177 sal_Int64 nTest;
178 ZipPackageEntry *pEntry;
179 if ( ( nTest = xRef->getSomething ( ZipPackageFolder::static_getImplementationId() ) ) != 0 )
181 ZipPackageFolder *pFolder = reinterpret_cast < ZipPackageFolder * > ( nTest );
182 pEntry = static_cast < ZipPackageEntry * > ( pFolder );
184 else if ( ( nTest = xRef->getSomething ( ZipPackageStream::static_getImplementationId() ) ) != 0 )
186 ZipPackageStream *pStream = reinterpret_cast < ZipPackageStream * > ( nTest );
187 pEntry = static_cast < ZipPackageEntry * > ( pStream );
189 else
190 throw IllegalArgumentException(THROW_WHERE, uno::Reference< uno::XInterface >(), 0 );
192 if (pEntry->getName() != aName )
193 pEntry->setName (aName);
194 doInsertByName ( pEntry, true );
197 void SAL_CALL ZipPackageFolder::removeByName( const OUString& Name )
199 ContentHash::iterator aIter = maContents.find ( Name );
200 if ( aIter == maContents.end() )
201 throw NoSuchElementException(THROW_WHERE );
202 maContents.erase( aIter );
204 // XEnumerationAccess
205 uno::Reference< XEnumeration > SAL_CALL ZipPackageFolder::createEnumeration( )
207 return uno::Reference < XEnumeration> (new ZipPackageFolderEnumeration(maContents));
209 // XElementAccess
210 uno::Type SAL_CALL ZipPackageFolder::getElementType( )
212 return cppu::UnoType<XUnoTunnel>::get();
214 sal_Bool SAL_CALL ZipPackageFolder::hasElements( )
216 return maContents.size() > 0;
218 // XNameAccess
219 ZipContentInfo& ZipPackageFolder::doGetByName( const OUString& aName )
221 ContentHash::iterator aIter = maContents.find ( aName );
222 if ( aIter == maContents.end())
223 throw NoSuchElementException(THROW_WHERE );
224 return *aIter->second;
227 uno::Any SAL_CALL ZipPackageFolder::getByName( const OUString& aName )
229 return uno::makeAny ( doGetByName ( aName ).xTunnel );
231 uno::Sequence< OUString > SAL_CALL ZipPackageFolder::getElementNames( )
233 sal_uInt32 i=0, nSize = maContents.size();
234 uno::Sequence < OUString > aSequence ( nSize );
235 for ( ContentHash::const_iterator aIterator = maContents.begin(), aEnd = maContents.end();
236 aIterator != aEnd;
237 ++i, ++aIterator)
238 aSequence[i] = (*aIterator).first;
239 return aSequence;
241 sal_Bool SAL_CALL ZipPackageFolder::hasByName( const OUString& aName )
243 return maContents.find ( aName ) != maContents.end ();
245 // XNameReplace
246 void SAL_CALL ZipPackageFolder::replaceByName( const OUString& aName, const uno::Any& aElement )
248 if ( !hasByName( aName ) )
249 throw NoSuchElementException(THROW_WHERE );
251 removeByName( aName );
252 insertByName(aName, aElement);
255 bool ZipPackageFolder::saveChild(
256 const OUString &rPath,
257 std::vector < uno::Sequence < PropertyValue > > &rManList,
258 ZipOutputStream & rZipOut,
259 const uno::Sequence < sal_Int8 >& rEncryptionKey,
260 sal_Int32 nPBKDF2IterationCount,
261 const rtlRandomPool &rRandomPool)
263 const OUString sMediaTypeProperty ("MediaType");
264 const OUString sVersionProperty ("Version");
265 const OUString sFullPathProperty ("FullPath");
267 uno::Sequence < PropertyValue > aPropSet (PKG_SIZE_NOENCR_MNFST);
268 OUString sTempName = rPath + "/";
270 if ( !GetMediaType().isEmpty() )
272 aPropSet[PKG_MNFST_MEDIATYPE].Name = sMediaTypeProperty;
273 aPropSet[PKG_MNFST_MEDIATYPE].Value <<= GetMediaType();
274 aPropSet[PKG_MNFST_VERSION].Name = sVersionProperty;
275 aPropSet[PKG_MNFST_VERSION].Value <<= GetVersion();
276 aPropSet[PKG_MNFST_FULLPATH].Name = sFullPathProperty;
277 aPropSet[PKG_MNFST_FULLPATH].Value <<= sTempName;
279 else
280 aPropSet.realloc( 0 );
282 saveContents( sTempName, rManList, rZipOut, rEncryptionKey, nPBKDF2IterationCount, rRandomPool);
284 // folder can have a mediatype only in package format
285 if ( aPropSet.getLength() && ( m_nFormat == embed::StorageFormats::PACKAGE ) )
286 rManList.push_back( aPropSet );
288 return true;
291 void ZipPackageFolder::saveContents(
292 const OUString &rPath,
293 std::vector < uno::Sequence < PropertyValue > > &rManList,
294 ZipOutputStream & rZipOut,
295 const uno::Sequence < sal_Int8 >& rEncryptionKey,
296 sal_Int32 nPBKDF2IterationCount,
297 const rtlRandomPool &rRandomPool ) const
299 bool bWritingFailed = false;
301 if ( maContents.empty() && !rPath.isEmpty() && m_nFormat != embed::StorageFormats::OFOPXML )
303 // it is an empty subfolder, use workaround to store it
304 ZipEntry* pTempEntry = new ZipEntry(aEntry);
305 pTempEntry->nPathLen = static_cast<sal_Int16>( OUStringToOString( rPath, RTL_TEXTENCODING_UTF8 ).getLength() );
306 pTempEntry->nExtraLen = -1;
307 pTempEntry->sPath = rPath;
311 ZipOutputStream::setEntry(pTempEntry);
312 rZipOut.writeLOC(pTempEntry);
313 rZipOut.rawCloseEntry();
315 catch ( ZipException& )
317 bWritingFailed = true;
319 catch ( IOException& )
321 bWritingFailed = true;
325 bool bMimeTypeStreamStored = false;
326 OUString aMimeTypeStreamName("mimetype");
327 if ( m_nFormat == embed::StorageFormats::ZIP && rPath.isEmpty() )
329 // let the "mimetype" stream in root folder be stored as the first stream if it is zip format
330 ContentHash::const_iterator aIter = maContents.find ( aMimeTypeStreamName );
331 if ( aIter != maContents.end() && !(*aIter).second->bFolder )
333 bMimeTypeStreamStored = true;
334 bWritingFailed = !aIter->second->pStream->saveChild(
335 rPath + aIter->first, rManList, rZipOut, rEncryptionKey, nPBKDF2IterationCount, rRandomPool );
339 for ( ContentHash::const_iterator aCI = maContents.begin(), aEnd = maContents.end();
340 aCI != aEnd;
341 ++aCI)
343 const OUString &rShortName = (*aCI).first;
344 const ZipContentInfo &rInfo = *(*aCI).second;
346 if ( !bMimeTypeStreamStored || rShortName != aMimeTypeStreamName )
348 if (rInfo.bFolder)
350 bWritingFailed = !rInfo.pFolder->saveChild(
351 rPath + rShortName, rManList, rZipOut, rEncryptionKey, nPBKDF2IterationCount, rRandomPool );
353 else
355 bWritingFailed = !rInfo.pStream->saveChild(
356 rPath + rShortName, rManList, rZipOut, rEncryptionKey, nPBKDF2IterationCount, rRandomPool );
361 if( bWritingFailed )
362 throw uno::RuntimeException(THROW_WHERE );
365 sal_Int64 SAL_CALL ZipPackageFolder::getSomething( const uno::Sequence< sal_Int8 >& aIdentifier )
367 sal_Int64 nMe = 0;
368 if ( aIdentifier.getLength() == 16 &&
369 0 == memcmp(static_getImplementationId().getConstArray(), aIdentifier.getConstArray(), 16 ) )
370 nMe = reinterpret_cast < sal_Int64 > ( this );
371 return nMe;
373 void SAL_CALL ZipPackageFolder::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
375 if ( aPropertyName == "MediaType" )
377 // TODO/LATER: activate when zip ucp is ready
378 // if ( m_nFormat != embed::StorageFormats::PACKAGE )
379 // throw UnknownPropertyException(THROW_WHERE );
381 aValue >>= msMediaType;
383 else if ( aPropertyName == "Version" )
384 aValue >>= m_sVersion;
385 else if ( aPropertyName == "Size" )
386 aValue >>= aEntry.nSize;
387 else
388 throw UnknownPropertyException(THROW_WHERE );
390 uno::Any SAL_CALL ZipPackageFolder::getPropertyValue( const OUString& PropertyName )
392 if ( PropertyName == "MediaType" )
394 // TODO/LATER: activate when zip ucp is ready
395 // if ( m_nFormat != embed::StorageFormats::PACKAGE )
396 // throw UnknownPropertyException(THROW_WHERE );
398 return uno::makeAny ( msMediaType );
400 else if ( PropertyName == "Version" )
401 return uno::makeAny( m_sVersion );
402 else if ( PropertyName == "Size" )
403 return uno::makeAny ( aEntry.nSize );
404 else
405 throw UnknownPropertyException(THROW_WHERE );
408 void ZipPackageFolder::doInsertByName ( ZipPackageEntry *pEntry, bool bSetParent )
410 if ( pEntry->IsFolder() )
411 maContents[pEntry->getName()] = o3tl::make_unique<ZipContentInfo>(static_cast<ZipPackageFolder*>(pEntry));
412 else
413 maContents[pEntry->getName()] = o3tl::make_unique<ZipContentInfo>(static_cast<ZipPackageStream*>(pEntry));
414 if ( bSetParent )
415 pEntry->setParent ( *this );
418 OUString ZipPackageFolder::getImplementationName()
420 return OUString("ZipPackageFolder");
423 uno::Sequence< OUString > ZipPackageFolder::getSupportedServiceNames()
425 uno::Sequence< OUString > aNames { "com.sun.star.packages.PackageFolder" };
426 return aNames;
429 sal_Bool SAL_CALL ZipPackageFolder::supportsService( OUString const & rServiceName )
431 return cppu::supportsService(this, rServiceName);
434 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */