bump product version to 6.4.0.3
[LibreOffice.git] / package / source / zippackage / ZipPackageFolder.cxx
blobfdc7231059a604488a39a5ad79c6d1603c17670b
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 <comphelper/sequence.hxx>
31 #include <comphelper/servicehelper.hxx>
32 #include <cppuhelper/supportsservice.hxx>
33 #include <cppuhelper/typeprovider.hxx>
34 #include <osl/diagnose.h>
35 #include <sal/log.hxx>
36 #include <rtl/digest.h>
37 #include "ContentInfo.hxx"
38 #include <com/sun/star/beans/PropertyValue.hpp>
39 #include <EncryptedDataHeader.hxx>
40 #include <rtl/instance.hxx>
42 using namespace com::sun::star;
43 using namespace com::sun::star::packages::zip::ZipConstants;
44 using namespace com::sun::star::packages::zip;
45 using namespace com::sun::star::packages;
46 using namespace com::sun::star::container;
47 using namespace com::sun::star::beans;
48 using namespace com::sun::star::lang;
49 using namespace com::sun::star::io;
50 using namespace cppu;
52 #if OSL_DEBUG_LEVEL > 0
53 #define THROW_WHERE SAL_WHERE
54 #else
55 #define THROW_WHERE ""
56 #endif
58 namespace { struct lcl_CachedImplId : public rtl::Static< cppu::OImplementationId, lcl_CachedImplId > {}; }
60 ZipPackageFolder::ZipPackageFolder( const css::uno::Reference < css::uno::XComponentContext >& xContext,
61 sal_Int32 nFormat,
62 bool bAllowRemoveOnInsert )
64 m_xContext = xContext;
65 m_nFormat = nFormat;
66 mbAllowRemoveOnInsert = bAllowRemoveOnInsert;
67 SetFolder ( true );
68 aEntry.nVersion = -1;
69 aEntry.nFlag = 0;
70 aEntry.nMethod = STORED;
71 aEntry.nTime = -1;
72 aEntry.nCrc = 0;
73 aEntry.nCompressedSize = 0;
74 aEntry.nSize = 0;
75 aEntry.nOffset = -1;
78 ZipPackageFolder::~ZipPackageFolder()
82 bool ZipPackageFolder::LookForUnexpectedODF12Streams( const OUString& aPath )
84 bool bHasUnexpected = false;
86 for (const auto& [rShortName, rxInfo] : maContents)
88 const ZipContentInfo &rInfo = *rxInfo;
90 if ( rInfo.bFolder )
92 if ( aPath == "META-INF/" )
94 // META-INF is not allowed to contain subfolders
95 bHasUnexpected = true;
97 else
99 OUString sOwnPath = aPath + rShortName + "/";
100 bHasUnexpected = rInfo.pFolder->LookForUnexpectedODF12Streams( sOwnPath );
103 else
105 if ( aPath == "META-INF/" )
107 if ( rShortName != "manifest.xml"
108 && rShortName.indexOf( "signatures" ) == -1 )
110 // a stream from META-INF with unexpected name
111 bHasUnexpected = true;
114 // streams from META-INF with expected names are allowed not to be registered in manifest.xml
116 else if ( !rInfo.pStream->IsFromManifest() )
118 // the stream is not in META-INF and is not registered in manifest.xml,
119 // check whether it is an internal part of the package format
120 if ( !aPath.isEmpty() || rShortName != "mimetype" )
122 // if it is not "mimetype" from the root it is not a part of the package
123 bHasUnexpected = true;
128 if (bHasUnexpected)
129 break;
132 return bHasUnexpected;
135 void ZipPackageFolder::setChildStreamsTypeByExtension( const beans::StringPair& aPair )
137 OUString aExt;
138 if ( aPair.First.toChar() == '.' )
139 aExt = aPair.First;
140 else
141 aExt = "." + aPair.First;
143 for (const auto& [rShortName, rxInfo] : maContents)
145 const ZipContentInfo &rInfo = *rxInfo;
147 if ( rInfo.bFolder )
148 rInfo.pFolder->setChildStreamsTypeByExtension( aPair );
149 else
151 sal_Int32 nPathLength = rShortName.getLength();
152 sal_Int32 nExtLength = aExt.getLength();
153 if ( nPathLength >= nExtLength && rShortName.match( aExt, nPathLength - nExtLength ) )
154 rInfo.pStream->SetMediaType( aPair.Second );
159 css::uno::Sequence < sal_Int8 > ZipPackageFolder::getUnoTunnelId()
161 return lcl_CachedImplId::get().getImplementationId();
164 // XNameContainer
165 void SAL_CALL ZipPackageFolder::insertByName( const OUString& aName, const uno::Any& aElement )
167 if (hasByName(aName))
168 throw ElementExistException(THROW_WHERE );
170 uno::Reference < XUnoTunnel > xRef;
171 aElement >>= xRef;
172 if ( !(aElement >>= xRef) )
173 throw IllegalArgumentException(THROW_WHERE, uno::Reference< uno::XInterface >(), 0 );
175 sal_Int64 nTest;
176 ZipPackageEntry *pEntry;
177 if ( ( nTest = xRef->getSomething ( ZipPackageFolder::getUnoTunnelId() ) ) != 0 )
179 ZipPackageFolder *pFolder = reinterpret_cast < ZipPackageFolder * > ( nTest );
180 pEntry = static_cast < ZipPackageEntry * > ( pFolder );
182 else if ( ( nTest = xRef->getSomething ( ZipPackageStream::getUnoTunnelId() ) ) != 0 )
184 ZipPackageStream *pStream = reinterpret_cast < ZipPackageStream * > ( nTest );
185 pEntry = static_cast < ZipPackageEntry * > ( pStream );
187 else
188 throw IllegalArgumentException(THROW_WHERE, uno::Reference< uno::XInterface >(), 0 );
190 if (pEntry->getName() != aName )
191 pEntry->setName (aName);
192 doInsertByName ( pEntry, true );
195 void SAL_CALL ZipPackageFolder::removeByName( const OUString& Name )
197 ContentHash::iterator aIter = maContents.find ( Name );
198 if ( aIter == maContents.end() )
199 throw NoSuchElementException(THROW_WHERE );
200 maContents.erase( aIter );
202 // XEnumerationAccess
203 uno::Reference< XEnumeration > SAL_CALL ZipPackageFolder::createEnumeration( )
205 return uno::Reference < XEnumeration> (new ZipPackageFolderEnumeration(maContents));
207 // XElementAccess
208 uno::Type SAL_CALL ZipPackageFolder::getElementType( )
210 return cppu::UnoType<XUnoTunnel>::get();
212 sal_Bool SAL_CALL ZipPackageFolder::hasElements( )
214 return !maContents.empty();
216 // XNameAccess
217 ZipContentInfo& ZipPackageFolder::doGetByName( const OUString& aName )
219 ContentHash::iterator aIter = maContents.find ( aName );
220 if ( aIter == maContents.end())
221 throw NoSuchElementException(THROW_WHERE );
222 return *aIter->second;
225 uno::Any SAL_CALL ZipPackageFolder::getByName( const OUString& aName )
227 return uno::makeAny ( doGetByName ( aName ).xTunnel );
229 uno::Sequence< OUString > SAL_CALL ZipPackageFolder::getElementNames( )
231 return comphelper::mapKeysToSequence(maContents);
233 sal_Bool SAL_CALL ZipPackageFolder::hasByName( const OUString& aName )
235 return maContents.find ( aName ) != maContents.end ();
237 // XNameReplace
238 void SAL_CALL ZipPackageFolder::replaceByName( const OUString& aName, const uno::Any& aElement )
240 if ( !hasByName( aName ) )
241 throw NoSuchElementException(THROW_WHERE );
243 removeByName( aName );
244 insertByName(aName, aElement);
247 bool ZipPackageFolder::saveChild(
248 const OUString &rPath,
249 std::vector < uno::Sequence < PropertyValue > > &rManList,
250 ZipOutputStream & rZipOut,
251 const uno::Sequence < sal_Int8 >& rEncryptionKey,
252 sal_Int32 nPBKDF2IterationCount,
253 const rtlRandomPool &rRandomPool)
255 const OUString sMediaTypeProperty ("MediaType");
256 const OUString sVersionProperty ("Version");
257 const OUString sFullPathProperty ("FullPath");
259 uno::Sequence < PropertyValue > aPropSet (PKG_SIZE_NOENCR_MNFST);
260 OUString sTempName = rPath + "/";
262 if ( !GetMediaType().isEmpty() )
264 aPropSet[PKG_MNFST_MEDIATYPE].Name = sMediaTypeProperty;
265 aPropSet[PKG_MNFST_MEDIATYPE].Value <<= GetMediaType();
266 aPropSet[PKG_MNFST_VERSION].Name = sVersionProperty;
267 aPropSet[PKG_MNFST_VERSION].Value <<= GetVersion();
268 aPropSet[PKG_MNFST_FULLPATH].Name = sFullPathProperty;
269 aPropSet[PKG_MNFST_FULLPATH].Value <<= sTempName;
271 else
272 aPropSet.realloc( 0 );
274 saveContents( sTempName, rManList, rZipOut, rEncryptionKey, nPBKDF2IterationCount, rRandomPool);
276 // folder can have a mediatype only in package format
277 if ( aPropSet.hasElements() && ( m_nFormat == embed::StorageFormats::PACKAGE ) )
278 rManList.push_back( aPropSet );
280 return true;
283 void ZipPackageFolder::saveContents(
284 const OUString &rPath,
285 std::vector < uno::Sequence < PropertyValue > > &rManList,
286 ZipOutputStream & rZipOut,
287 const uno::Sequence < sal_Int8 >& rEncryptionKey,
288 sal_Int32 nPBKDF2IterationCount,
289 const rtlRandomPool &rRandomPool ) const
291 if ( maContents.empty() && !rPath.isEmpty() && m_nFormat != embed::StorageFormats::OFOPXML )
293 // it is an empty subfolder, use workaround to store it
294 ZipEntry* pTempEntry = new ZipEntry(aEntry);
295 pTempEntry->nPathLen = static_cast<sal_Int16>( OUStringToOString( rPath, RTL_TEXTENCODING_UTF8 ).getLength() );
296 pTempEntry->nExtraLen = -1;
297 pTempEntry->sPath = rPath;
301 ZipOutputStream::setEntry(pTempEntry);
302 rZipOut.writeLOC(pTempEntry);
303 rZipOut.rawCloseEntry();
305 catch ( ZipException& )
307 throw uno::RuntimeException( THROW_WHERE );
309 catch ( IOException& )
311 throw uno::RuntimeException( THROW_WHERE );
315 bool bMimeTypeStreamStored = false;
316 OUString aMimeTypeStreamName("mimetype");
317 if ( m_nFormat == embed::StorageFormats::ZIP && rPath.isEmpty() )
319 // let the "mimetype" stream in root folder be stored as the first stream if it is zip format
320 ContentHash::const_iterator aIter = maContents.find ( aMimeTypeStreamName );
321 if ( aIter != maContents.end() && !(*aIter).second->bFolder )
323 bMimeTypeStreamStored = true;
324 if( !aIter->second->pStream->saveChild(
325 rPath + aIter->first, rManList, rZipOut, rEncryptionKey, nPBKDF2IterationCount, rRandomPool ))
327 throw uno::RuntimeException( THROW_WHERE );
332 for (const auto& [rShortName, rxInfo] : maContents)
334 const ZipContentInfo &rInfo = *rxInfo;
336 if ( !bMimeTypeStreamStored || rShortName != aMimeTypeStreamName )
338 if (rInfo.bFolder)
340 if( !rInfo.pFolder->saveChild(
341 rPath + rShortName, rManList, rZipOut, rEncryptionKey, nPBKDF2IterationCount, rRandomPool ))
343 throw uno::RuntimeException( THROW_WHERE );
346 else
348 if( !rInfo.pStream->saveChild(
349 rPath + rShortName, rManList, rZipOut, rEncryptionKey, nPBKDF2IterationCount, rRandomPool ))
351 throw uno::RuntimeException( THROW_WHERE );
358 sal_Int64 SAL_CALL ZipPackageFolder::getSomething( const uno::Sequence< sal_Int8 >& aIdentifier )
360 sal_Int64 nMe = 0;
361 if ( isUnoTunnelId<ZipPackageFolder>(aIdentifier) )
362 nMe = reinterpret_cast < sal_Int64 > ( this );
363 return nMe;
365 void SAL_CALL ZipPackageFolder::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
367 if ( aPropertyName == "MediaType" )
369 // TODO/LATER: activate when zip ucp is ready
370 // if ( m_nFormat != embed::StorageFormats::PACKAGE )
371 // throw UnknownPropertyException(THROW_WHERE );
373 aValue >>= msMediaType;
375 else if ( aPropertyName == "Version" )
376 aValue >>= m_sVersion;
377 else if ( aPropertyName == "Size" )
378 aValue >>= aEntry.nSize;
379 else
380 throw UnknownPropertyException(aPropertyName);
382 uno::Any SAL_CALL ZipPackageFolder::getPropertyValue( const OUString& PropertyName )
384 if ( PropertyName == "MediaType" )
386 // TODO/LATER: activate when zip ucp is ready
387 // if ( m_nFormat != embed::StorageFormats::PACKAGE )
388 // throw UnknownPropertyException(THROW_WHERE );
390 return uno::makeAny ( msMediaType );
392 else if ( PropertyName == "Version" )
393 return uno::makeAny( m_sVersion );
394 else if ( PropertyName == "Size" )
395 return uno::makeAny ( aEntry.nSize );
396 else
397 throw UnknownPropertyException(PropertyName);
400 void ZipPackageFolder::doInsertByName ( ZipPackageEntry *pEntry, bool bSetParent )
402 if ( pEntry->IsFolder() )
403 maContents[pEntry->getName()] = std::make_unique<ZipContentInfo>(static_cast<ZipPackageFolder*>(pEntry));
404 else
405 maContents[pEntry->getName()] = std::make_unique<ZipContentInfo>(static_cast<ZipPackageStream*>(pEntry));
406 if ( bSetParent )
407 pEntry->setParent ( *this );
410 OUString ZipPackageFolder::getImplementationName()
412 return "ZipPackageFolder";
415 uno::Sequence< OUString > ZipPackageFolder::getSupportedServiceNames()
417 uno::Sequence< OUString > aNames { "com.sun.star.packages.PackageFolder" };
418 return aNames;
421 sal_Bool SAL_CALL ZipPackageFolder::supportsService( OUString const & rServiceName )
423 return cppu::supportsService(this, rServiceName);
426 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */