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 <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>
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 :
51 : #if OSL_DEBUG_LEVEL > 0
52 : #define THROW_WHERE SAL_WHERE
53 : #else
54 : #define THROW_WHERE ""
55 : #endif
56 :
57 : namespace { struct lcl_CachedImplId : public rtl::Static< cppu::OImplementationId, lcl_CachedImplId > {}; }
58 :
59 145093 : ZipPackageFolder::ZipPackageFolder( const css::uno::Reference < css::uno::XComponentContext >& xContext,
60 : sal_Int32 nFormat,
61 145093 : bool bAllowRemoveOnInsert )
62 : {
63 145093 : m_xContext = xContext;
64 145093 : m_nFormat = nFormat;
65 145093 : mbAllowRemoveOnInsert = bAllowRemoveOnInsert;
66 145093 : SetFolder ( true );
67 145093 : aEntry.nVersion = -1;
68 145093 : aEntry.nFlag = 0;
69 145093 : aEntry.nMethod = STORED;
70 145093 : aEntry.nTime = -1;
71 145093 : aEntry.nCrc = 0;
72 145093 : aEntry.nCompressedSize = 0;
73 145093 : aEntry.nSize = 0;
74 145093 : aEntry.nOffset = -1;
75 145093 : }
76 :
77 289790 : ZipPackageFolder::~ZipPackageFolder()
78 : {
79 289790 : }
80 :
81 12592 : bool ZipPackageFolder::LookForUnexpectedODF12Streams( const OUString& aPath )
82 : {
83 12592 : bool bHasUnexpected = false;
84 :
85 63404 : for ( ContentHash::const_iterator aCI = maContents.begin(), aEnd = maContents.end();
86 31702 : !bHasUnexpected && aCI != aEnd;
87 : ++aCI)
88 : {
89 19110 : const OUString &rShortName = (*aCI).first;
90 19110 : const ContentInfo &rInfo = *(*aCI).second;
91 :
92 19110 : if ( rInfo.bFolder )
93 : {
94 11538 : if ( aPath == "META-INF/" )
95 : {
96 : // META-INF is not allowed to contain subfolders
97 0 : bHasUnexpected = true;
98 : }
99 : else
100 : {
101 11538 : OUString sOwnPath = aPath + rShortName + "/";
102 11538 : bHasUnexpected = rInfo.pFolder->LookForUnexpectedODF12Streams( sOwnPath );
103 : }
104 : }
105 : else
106 : {
107 7572 : if ( aPath == "META-INF/" )
108 : {
109 0 : if ( rShortName != "manifest.xml"
110 0 : && rShortName.indexOf( "signatures" ) == -1 )
111 : {
112 : // a stream from META-INF with unexpected name
113 0 : bHasUnexpected = true;
114 : }
115 :
116 : // streams from META-INF with expected names are allowed not to be registered in manifest.xml
117 : }
118 7572 : else if ( !rInfo.pStream->IsFromManifest() )
119 : {
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 6 : if ( !aPath.isEmpty() || rShortName != "mimetype" )
123 : {
124 : // if it is not "mimetype" from the root it is not a part of the package
125 6 : bHasUnexpected = true;
126 : }
127 : }
128 : }
129 : }
130 :
131 12592 : return bHasUnexpected;
132 : }
133 :
134 52377 : void ZipPackageFolder::setChildStreamsTypeByExtension( const beans::StringPair& aPair )
135 : {
136 52377 : OUString aExt;
137 52377 : if ( aPair.First.toChar() == (sal_Unicode)'.' )
138 0 : aExt = aPair.First;
139 : else
140 52377 : aExt = "." + aPair.First;
141 :
142 259384 : for ( ContentHash::const_iterator aCI = maContents.begin(), aEnd = maContents.end();
143 : aCI != aEnd;
144 : ++aCI)
145 : {
146 207007 : const OUString &rShortName = (*aCI).first;
147 207007 : const ContentInfo &rInfo = *(*aCI).second;
148 :
149 207007 : if ( rInfo.bFolder )
150 45294 : rInfo.pFolder->setChildStreamsTypeByExtension( aPair );
151 : else
152 : {
153 161713 : sal_Int32 nPathLength = rShortName.getLength();
154 161713 : sal_Int32 nExtLength = aExt.getLength();
155 161713 : if ( nPathLength >= nExtLength && rShortName.match( aExt, nPathLength - nExtLength ) )
156 59846 : rInfo.pStream->SetMediaType( aPair.Second );
157 : }
158 52377 : }
159 52377 : }
160 :
161 21185 : void ZipPackageFolder::copyZipEntry( ZipEntry &rDest, const ZipEntry &rSource)
162 : {
163 21185 : rDest.nVersion = rSource.nVersion;
164 21185 : rDest.nFlag = rSource.nFlag;
165 21185 : rDest.nMethod = rSource.nMethod;
166 21185 : rDest.nTime = rSource.nTime;
167 21185 : rDest.nCrc = rSource.nCrc;
168 21185 : rDest.nCompressedSize = rSource.nCompressedSize;
169 21185 : rDest.nSize = rSource.nSize;
170 21185 : rDest.nOffset = rSource.nOffset;
171 21185 : rDest.sPath = rSource.sPath;
172 21185 : rDest.nPathLen = rSource.nPathLen;
173 21185 : rDest.nExtraLen = rSource.nExtraLen;
174 21185 : }
175 :
176 69330 : ::com::sun::star::uno::Sequence < sal_Int8 > ZipPackageFolder::static_getImplementationId()
177 : {
178 69330 : return lcl_CachedImplId::get().getImplementationId();
179 : }
180 :
181 : // XNameContainer
182 17250 : void SAL_CALL ZipPackageFolder::insertByName( const OUString& aName, const uno::Any& aElement )
183 : throw(IllegalArgumentException, ElementExistException, WrappedTargetException, uno::RuntimeException, std::exception)
184 : {
185 17250 : if (hasByName(aName))
186 0 : throw ElementExistException(THROW_WHERE );
187 : else
188 : {
189 17250 : uno::Reference < XUnoTunnel > xRef;
190 17250 : aElement >>= xRef;
191 17250 : if ( ( aElement >>= xRef ) )
192 : {
193 : sal_Int64 nTest;
194 : ZipPackageEntry *pEntry;
195 17250 : if ( ( nTest = xRef->getSomething ( ZipPackageFolder::static_getImplementationId() ) ) != 0 )
196 : {
197 4804 : ZipPackageFolder *pFolder = reinterpret_cast < ZipPackageFolder * > ( nTest );
198 4804 : pEntry = static_cast < ZipPackageEntry * > ( pFolder );
199 : }
200 12446 : else if ( ( nTest = xRef->getSomething ( ZipPackageStream::static_getImplementationId() ) ) != 0 )
201 : {
202 12446 : ZipPackageStream *pStream = reinterpret_cast < ZipPackageStream * > ( nTest );
203 12446 : pEntry = static_cast < ZipPackageEntry * > ( pStream );
204 : }
205 : else
206 0 : throw IllegalArgumentException(THROW_WHERE, uno::Reference< uno::XInterface >(), 0 );
207 :
208 17250 : if (pEntry->getName() != aName )
209 17242 : pEntry->setName (aName);
210 17250 : doInsertByName ( pEntry, true );
211 : }
212 : else
213 0 : throw IllegalArgumentException(THROW_WHERE, uno::Reference< uno::XInterface >(), 0 );
214 : }
215 17250 : }
216 7832 : void SAL_CALL ZipPackageFolder::removeByName( const OUString& Name )
217 : throw(NoSuchElementException, WrappedTargetException, uno::RuntimeException, std::exception)
218 : {
219 7832 : ContentHash::iterator aIter = maContents.find ( Name );
220 7832 : if ( aIter == maContents.end() )
221 0 : throw NoSuchElementException(THROW_WHERE );
222 7832 : maContents.erase( aIter );
223 7832 : }
224 : // XEnumerationAccess
225 63304 : uno::Reference< XEnumeration > SAL_CALL ZipPackageFolder::createEnumeration( )
226 : throw(uno::RuntimeException, std::exception)
227 : {
228 63304 : return uno::Reference < XEnumeration> (new ZipPackageFolderEnumeration(maContents));
229 : }
230 : // XElementAccess
231 0 : uno::Type SAL_CALL ZipPackageFolder::getElementType( )
232 : throw(uno::RuntimeException, std::exception)
233 : {
234 0 : return cppu::UnoType<XUnoTunnel>::get();
235 : }
236 0 : sal_Bool SAL_CALL ZipPackageFolder::hasElements( )
237 : throw(uno::RuntimeException, std::exception)
238 : {
239 0 : return maContents.size() > 0;
240 : }
241 : // XNameAccess
242 186861 : ContentInfo& ZipPackageFolder::doGetByName( const OUString& aName )
243 : throw(NoSuchElementException, WrappedTargetException, uno::RuntimeException)
244 : {
245 186861 : ContentHash::iterator aIter = maContents.find ( aName );
246 186861 : if ( aIter == maContents.end())
247 0 : throw NoSuchElementException(THROW_WHERE );
248 186861 : return *(*aIter).second;
249 : }
250 142935 : uno::Any SAL_CALL ZipPackageFolder::getByName( const OUString& aName )
251 : throw(NoSuchElementException, WrappedTargetException, uno::RuntimeException, std::exception)
252 : {
253 142935 : return uno::makeAny ( doGetByName ( aName ).xTunnel );
254 : }
255 0 : uno::Sequence< OUString > SAL_CALL ZipPackageFolder::getElementNames( )
256 : throw(uno::RuntimeException, std::exception)
257 : {
258 0 : sal_uInt32 i=0, nSize = maContents.size();
259 0 : uno::Sequence < OUString > aSequence ( nSize );
260 0 : for ( ContentHash::const_iterator aIterator = maContents.begin(), aEnd = maContents.end();
261 : aIterator != aEnd;
262 : ++i, ++aIterator)
263 0 : aSequence[i] = (*aIterator).first;
264 0 : return aSequence;
265 : }
266 605435 : sal_Bool SAL_CALL ZipPackageFolder::hasByName( const OUString& aName )
267 : throw(uno::RuntimeException, std::exception)
268 : {
269 605435 : return maContents.find ( aName ) != maContents.end ();
270 : }
271 : // XNameReplace
272 0 : void SAL_CALL ZipPackageFolder::replaceByName( const OUString& aName, const uno::Any& aElement )
273 : throw(IllegalArgumentException, NoSuchElementException, WrappedTargetException, uno::RuntimeException, std::exception)
274 : {
275 0 : if ( hasByName( aName ) )
276 0 : removeByName( aName );
277 : else
278 0 : throw NoSuchElementException(THROW_WHERE );
279 0 : insertByName(aName, aElement);
280 0 : }
281 :
282 4859 : 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)
288 : {
289 4859 : bool bSuccess = true;
290 :
291 4859 : const OUString sMediaTypeProperty ("MediaType");
292 9718 : const OUString sVersionProperty ("Version");
293 9718 : const OUString sFullPathProperty ("FullPath");
294 :
295 9718 : uno::Sequence < PropertyValue > aPropSet (PKG_SIZE_NOENCR_MNFST);
296 9718 : OUString sTempName = rPath + "/";
297 :
298 4859 : if ( !GetMediaType().isEmpty() )
299 : {
300 124 : aPropSet[PKG_MNFST_MEDIATYPE].Name = sMediaTypeProperty;
301 124 : aPropSet[PKG_MNFST_MEDIATYPE].Value <<= GetMediaType();
302 124 : aPropSet[PKG_MNFST_VERSION].Name = sVersionProperty;
303 124 : aPropSet[PKG_MNFST_VERSION].Value <<= GetVersion();
304 124 : aPropSet[PKG_MNFST_FULLPATH].Name = sFullPathProperty;
305 124 : aPropSet[PKG_MNFST_FULLPATH].Value <<= sTempName;
306 : }
307 : else
308 4735 : aPropSet.realloc( 0 );
309 :
310 4859 : saveContents( sTempName, rManList, rZipOut, rEncryptionKey, rRandomPool);
311 :
312 : // folder can have a mediatype only in package format
313 4859 : if ( aPropSet.getLength() && ( m_nFormat == embed::StorageFormats::PACKAGE ) )
314 124 : rManList.push_back( aPropSet );
315 :
316 9718 : return bSuccess;
317 : }
318 :
319 5691 : 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 )
326 : {
327 5691 : bool bWritingFailed = false;
328 :
329 5691 : if ( maContents.begin() == maContents.end() && !rPath.isEmpty() && m_nFormat != embed::StorageFormats::OFOPXML )
330 : {
331 : // it is an empty subfolder, use workaround to store it
332 851 : ZipEntry* pTempEntry = new ZipEntry();
333 851 : ZipPackageFolder::copyZipEntry ( *pTempEntry, aEntry );
334 851 : pTempEntry->nPathLen = (sal_Int16)( OUStringToOString( rPath, RTL_TEXTENCODING_UTF8 ).getLength() );
335 851 : pTempEntry->nExtraLen = -1;
336 851 : pTempEntry->sPath = rPath;
337 :
338 : try
339 : {
340 851 : ZipOutputStream::setEntry(pTempEntry);
341 851 : rZipOut.writeLOC(pTempEntry);
342 851 : rZipOut.rawCloseEntry();
343 : }
344 0 : catch ( ZipException& )
345 : {
346 0 : bWritingFailed = true;
347 : }
348 0 : catch ( IOException& )
349 : {
350 0 : bWritingFailed = true;
351 : }
352 : }
353 :
354 5691 : bool bMimeTypeStreamStored = false;
355 5691 : OUString aMimeTypeStreamName("mimetype");
356 5691 : if ( m_nFormat == embed::StorageFormats::ZIP && rPath.isEmpty() )
357 : {
358 : // let the "mimetype" stream in root folder be stored as the first stream if it is zip format
359 0 : ContentHash::const_iterator aIter = maContents.find ( aMimeTypeStreamName );
360 0 : if ( aIter != maContents.end() && !(*aIter).second->bFolder )
361 : {
362 0 : bMimeTypeStreamStored = true;
363 0 : bWritingFailed = !aIter->second->pStream->saveChild(
364 0 : rPath + aIter->first, rManList, rZipOut, rEncryptionKey, rRandomPool );
365 : }
366 : }
367 :
368 20717 : for ( ContentHash::const_iterator aCI = maContents.begin(), aEnd = maContents.end();
369 : aCI != aEnd;
370 : ++aCI)
371 : {
372 15026 : const OUString &rShortName = (*aCI).first;
373 15026 : const ContentInfo &rInfo = *(*aCI).second;
374 :
375 15026 : if ( !bMimeTypeStreamStored || !rShortName.equals( aMimeTypeStreamName ) )
376 : {
377 15026 : if (rInfo.bFolder)
378 : {
379 : bWritingFailed = !rInfo.pFolder->saveChild(
380 4859 : rPath + rShortName, rManList, rZipOut, rEncryptionKey, rRandomPool );
381 : }
382 : else
383 : {
384 : bWritingFailed = !rInfo.pStream->saveChild(
385 10167 : rPath + rShortName, rManList, rZipOut, rEncryptionKey, rRandomPool );
386 : }
387 : }
388 : }
389 :
390 5691 : if( bWritingFailed )
391 0 : throw uno::RuntimeException(THROW_WHERE );
392 5691 : }
393 :
394 24644 : sal_Int64 SAL_CALL ZipPackageFolder::getSomething( const uno::Sequence< sal_Int8 >& aIdentifier )
395 : throw(uno::RuntimeException, std::exception)
396 : {
397 24644 : sal_Int64 nMe = 0;
398 98576 : if ( aIdentifier.getLength() == 16 &&
399 98576 : 0 == memcmp(static_getImplementationId().getConstArray(), aIdentifier.getConstArray(), 16 ) )
400 24644 : nMe = reinterpret_cast < sal_Int64 > ( this );
401 24644 : return nMe;
402 : }
403 5498 : void SAL_CALL ZipPackageFolder::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
404 : throw(UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, uno::RuntimeException, std::exception)
405 : {
406 5498 : if ( aPropertyName == "MediaType" )
407 : {
408 : // TODO/LATER: activate when zip ucp is ready
409 : // if ( m_nFormat != embed::StorageFormats::PACKAGE )
410 : // throw UnknownPropertyException(THROW_WHERE );
411 :
412 2749 : aValue >>= msMediaType;
413 : }
414 2749 : else if ( aPropertyName == "Version" )
415 2749 : aValue >>= m_sVersion;
416 0 : else if ( aPropertyName == "Size" )
417 0 : aValue >>= aEntry.nSize;
418 : else
419 0 : throw UnknownPropertyException(THROW_WHERE );
420 5498 : }
421 75821 : uno::Any SAL_CALL ZipPackageFolder::getPropertyValue( const OUString& PropertyName )
422 : throw(UnknownPropertyException, WrappedTargetException, uno::RuntimeException, std::exception)
423 : {
424 75821 : if ( PropertyName == "MediaType" )
425 : {
426 : // TODO/LATER: activate when zip ucp is ready
427 : // if ( m_nFormat != embed::StorageFormats::PACKAGE )
428 : // throw UnknownPropertyException(THROW_WHERE );
429 :
430 37880 : return uno::makeAny ( msMediaType );
431 : }
432 37941 : else if ( PropertyName == "Version" )
433 37941 : return uno::makeAny( m_sVersion );
434 0 : else if ( PropertyName == "Size" )
435 0 : return uno::makeAny ( aEntry.nSize );
436 : else
437 0 : throw UnknownPropertyException(THROW_WHERE );
438 : }
439 :
440 306949 : void ZipPackageFolder::doInsertByName ( ZipPackageEntry *pEntry, bool bSetParent )
441 : throw(IllegalArgumentException, ElementExistException, WrappedTargetException, uno::RuntimeException)
442 : {
443 : try
444 : {
445 306949 : if ( pEntry->IsFolder() )
446 82958 : maContents[pEntry->getName()] = new ContentInfo ( static_cast < ZipPackageFolder *> ( pEntry ) );
447 : else
448 223991 : maContents[pEntry->getName()] = new ContentInfo ( static_cast < ZipPackageStream *> ( pEntry ) );
449 : }
450 0 : catch(const uno::Exception& rEx)
451 : {
452 : (void)rEx;
453 0 : throw;
454 : }
455 306949 : if ( bSetParent )
456 17250 : pEntry->setParent ( *this );
457 306949 : }
458 0 : OUString ZipPackageFolder::getImplementationName()
459 : throw (uno::RuntimeException, std::exception)
460 : {
461 0 : return OUString("ZipPackageFolder");
462 : }
463 :
464 0 : uno::Sequence< OUString > ZipPackageFolder::getSupportedServiceNames()
465 : throw (uno::RuntimeException, std::exception)
466 : {
467 0 : uno::Sequence< OUString > aNames(1);
468 0 : aNames[0] = "com.sun.star.packages.PackageFolder";
469 0 : return aNames;
470 : }
471 :
472 0 : sal_Bool SAL_CALL ZipPackageFolder::supportsService( OUString const & rServiceName )
473 : throw (uno::RuntimeException, std::exception)
474 : {
475 0 : return cppu::supportsService(this, rServiceName);
476 : }
477 :
478 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|