update dev300-m58
[ooovba.git] / package / source / zippackage / ZipPackage.cxx
blob427a2ca9aca95baadd7d25c5921466fb07c42164
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ZipPackage.cxx,v $
10 * $Revision: 1.114 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_package.hxx"
33 #include <ZipPackage.hxx>
34 #include <ZipPackageSink.hxx>
35 #include <ZipEnumeration.hxx>
36 #include <ZipPackageStream.hxx>
37 #include <ZipPackageFolder.hxx>
38 #include <ZipOutputStream.hxx>
39 #include <ZipPackageBuffer.hxx>
40 #include <ZipFile.hxx>
41 #include <PackageConstants.hxx>
42 #include <com/sun/star/beans/PropertyValue.hpp>
43 #include <com/sun/star/beans/NamedValue.hpp>
44 #include <com/sun/star/packages/zip/ZipConstants.hpp>
45 #include <com/sun/star/packages/manifest/XManifestReader.hpp>
46 #include <com/sun/star/packages/manifest/XManifestWriter.hpp>
47 #include <com/sun/star/io/XStream.hpp>
48 #include <com/sun/star/io/XInputStream.hpp>
49 #include <com/sun/star/io/XOutputStream.hpp>
50 #include <com/sun/star/io/XTruncate.hpp>
51 #include <com/sun/star/io/XSeekable.hpp>
52 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
53 #include <com/sun/star/container/XNameContainer.hpp>
54 #include <com/sun/star/ucb/IOErrorCode.hpp>
55 #include <ucbhelper/content.hxx>
56 #include <cppuhelper/factory.hxx>
57 #include <cppuhelper/exc_hlp.hxx>
58 #include <com/sun/star/ucb/TransferInfo.hpp>
59 #include <com/sun/star/ucb/NameClash.hpp>
60 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
61 #include <com/sun/star/ucb/OpenMode.hpp>
62 #include <com/sun/star/ucb/XProgressHandler.hpp>
63 #include <com/sun/star/ucb/XSimpleFileAccess.hpp>
64 #include <com/sun/star/io/XActiveDataStreamer.hpp>
65 #include <com/sun/star/embed/XTransactedObject.hpp>
66 #include <com/sun/star/embed/UseBackupException.hpp>
67 #include <com/sun/star/beans/NamedValue.hpp>
68 #include <cppuhelper/implbase1.hxx>
69 #include <ContentInfo.hxx>
70 #include <cppuhelper/typeprovider.hxx>
71 #include <rtl/uri.hxx>
72 #include <rtl/random.h>
73 #include <rtl/logfile.hxx>
74 #include <osl/time.h>
75 #include <osl/file.hxx>
76 #include "com/sun/star/io/XAsyncOutputMonitor.hpp"
78 #include <memory>
79 #include <vector>
81 #include <ucbhelper/contentbroker.hxx>
82 #include <ucbhelper/fileidentifierconverter.hxx>
83 #include <comphelper/seekableinput.hxx>
84 #include <comphelper/storagehelper.hxx>
85 #include <comphelper/ofopxmlhelper.hxx>
86 #include <comphelper/documentconstants.hxx>
88 using namespace rtl;
89 using namespace std;
90 using namespace osl;
91 using namespace cppu;
92 using namespace ucbhelper;
93 using namespace com::sun::star;
94 using namespace com::sun::star::io;
95 using namespace com::sun::star::uno;
96 using namespace com::sun::star::ucb;
97 using namespace com::sun::star::util;
98 using namespace com::sun::star::lang;
99 using namespace com::sun::star::task;
100 using namespace com::sun::star::beans;
101 using namespace com::sun::star::packages;
102 using namespace com::sun::star::container;
103 using namespace com::sun::star::packages::zip;
104 using namespace com::sun::star::packages::manifest;
105 using namespace com::sun::star::packages::zip::ZipConstants;
107 #define LOGFILE_AUTHOR "mg115289"
110 namespace {
112 sal_Bool isLocalFile_Impl( ::rtl::OUString aURL )
114 ::rtl::OUString aSystemPath;
115 ContentBroker* pBroker = ContentBroker::get();
116 if ( !pBroker )
118 ::rtl::OUString aRet;
119 if ( FileBase::getSystemPathFromFileURL( aURL, aRet ) == FileBase::E_None )
120 aSystemPath = aRet;
122 else
124 uno::Reference< XContentProviderManager > xManager =
125 pBroker->getContentProviderManagerInterface();
128 aSystemPath = getSystemPathFromFileURL( xManager, aURL );
130 catch ( Exception& )
135 return ( aSystemPath.getLength() != 0 );
138 class PostinitializationGuard
140 uno::Reference< io::XInputStream > m_xTempStream;
142 ZipPackage& m_rZipPackage;
144 public:
145 PostinitializationGuard( const uno::Reference< io::XInputStream >& xTempStream,
146 ZipPackage& rZipPackage )
147 : m_xTempStream( xTempStream )
148 , m_rZipPackage( rZipPackage )
151 virtual ~PostinitializationGuard()
153 m_rZipPackage.ConnectTo( m_xTempStream );
159 //===========================================================================
161 class ActiveDataStreamer : public ::cppu::WeakImplHelper1< XActiveDataStreamer >
163 uno::Reference< XStream > mStream;
164 public:
166 virtual uno::Reference< XStream > SAL_CALL getStream()
167 throw( RuntimeException )
168 { return mStream; }
170 virtual void SAL_CALL setStream( const uno::Reference< XStream >& stream )
171 throw( RuntimeException )
172 { mStream = stream; }
175 class DummyInputStream : public ::cppu::WeakImplHelper1< XInputStream >
177 virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >&, sal_Int32 )
178 throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException)
179 { return 0; }
181 virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >&, sal_Int32 )
182 throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException)
183 { return 0; }
185 virtual void SAL_CALL skipBytes( sal_Int32 )
186 throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException)
189 virtual sal_Int32 SAL_CALL available()
190 throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException)
191 { return 0; }
193 virtual void SAL_CALL closeInput()
194 throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException)
198 //===========================================================================
200 ZipPackage::ZipPackage (const uno::Reference < XMultiServiceFactory > &xNewFactory)
201 : m_aMutexHolder( new SotMutexHolder )
202 , bHasEncryptedEntries ( sal_False )
203 , bUseManifest ( sal_True )
204 , bForceRecovery ( sal_False )
205 , m_bMediaTypeFallbackUsed ( sal_False )
206 , m_nFormat( PACKAGE_FORMAT ) // package is the default format
207 , m_bAllowRemoveOnInsert( sal_True )
208 , eMode ( e_IMode_None )
209 , xFactory( xNewFactory )
210 , pRootFolder( NULL )
211 , pZipFile( NULL )
213 xRootFolder = pRootFolder = new ZipPackageFolder( xFactory, m_nFormat, m_bAllowRemoveOnInsert );
216 ZipPackage::~ZipPackage( void )
218 delete pZipFile;
220 // All folders and streams contain pointers to their parents, when a parent diappeares
221 // it should disconnect all the children from itself during destruction automatically.
222 // So there is no need in explicit pRootFolder->releaseUpwardRef() call here any more
223 // since pRootFolder has no parent and cleaning of it's children will be done automatically
224 // during pRootFolder dieing by refcount.
226 #if 0
227 // As all folders and streams contain references to their parents,
228 // we must remove these references so that they will be deleted when
229 // the hash_map of the root folder is cleared, releasing all subfolders
230 // and substreams which in turn release theirs, etc. When xRootFolder is
231 // released when this destructor completes, the folder tree should be
232 // deleted fully (and automagically).
234 pRootFolder->releaseUpwardRef();
235 #endif
238 void ZipPackage::parseManifest()
240 if ( m_nFormat == PACKAGE_FORMAT )
242 sal_Bool bManifestParsed = sal_False;
243 const OUString sMeta ( RTL_CONSTASCII_USTRINGPARAM ( "META-INF" ) );
244 if ( xRootFolder->hasByName( sMeta ) )
246 const OUString sManifest (RTL_CONSTASCII_USTRINGPARAM( "manifest.xml") );
248 try {
249 uno::Reference< XUnoTunnel > xTunnel;
250 Any aAny = xRootFolder->getByName( sMeta );
251 aAny >>= xTunnel;
252 uno::Reference< XNameContainer > xMetaInfFolder( xTunnel, UNO_QUERY );
253 if ( xMetaInfFolder.is() && xMetaInfFolder->hasByName( sManifest ) )
255 aAny = xMetaInfFolder->getByName( sManifest );
256 aAny >>= xTunnel;
257 uno::Reference < XActiveDataSink > xSink (xTunnel, UNO_QUERY);
258 if (xSink.is())
260 OUString sManifestReader ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.manifest.ManifestReader" ) );
261 uno::Reference < XManifestReader > xReader (xFactory->createInstance( sManifestReader ), UNO_QUERY );
262 if ( xReader.is() )
264 const OUString sPropFullPath ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) );
265 const OUString sPropVersion ( RTL_CONSTASCII_USTRINGPARAM ( "Version" ) );
266 const OUString sPropMediaType ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) );
267 const OUString sPropInitialisationVector ( RTL_CONSTASCII_USTRINGPARAM ( "InitialisationVector" ) );
268 const OUString sPropSalt ( RTL_CONSTASCII_USTRINGPARAM ( "Salt" ) );
269 const OUString sPropIterationCount ( RTL_CONSTASCII_USTRINGPARAM ( "IterationCount" ) );
270 const OUString sPropSize ( RTL_CONSTASCII_USTRINGPARAM ( "Size" ) );
271 const OUString sPropDigest ( RTL_CONSTASCII_USTRINGPARAM ( "Digest" ) );
273 Sequence < Sequence < PropertyValue > > aManifestSequence = xReader->readManifestSequence ( xSink->getInputStream() );
274 sal_Int32 nLength = aManifestSequence.getLength();
275 const Sequence < PropertyValue > *pSequence = aManifestSequence.getConstArray();
276 ZipPackageStream *pStream = NULL;
277 ZipPackageFolder *pFolder = NULL;
279 for (sal_Int32 i = 0; i < nLength ; i++, pSequence++)
281 OUString sPath, sMediaType, sVersion;
282 const PropertyValue *pValue = pSequence->getConstArray();
283 const Any *pSalt = NULL, *pVector = NULL, *pCount = NULL, *pSize = NULL, *pDigest = NULL;
284 for (sal_Int32 j = 0, nNum = pSequence->getLength(); j < nNum; j++ )
286 if (pValue[j].Name.equals( sPropFullPath ) )
287 pValue[j].Value >>= sPath;
288 else if (pValue[j].Name.equals( sPropVersion ) )
289 pValue[j].Value >>= sVersion;
290 else if (pValue[j].Name.equals( sPropMediaType ) )
291 pValue[j].Value >>= sMediaType;
292 else if (pValue[j].Name.equals( sPropSalt ) )
293 pSalt = &(pValue[j].Value);
294 else if (pValue[j].Name.equals( sPropInitialisationVector ) )
295 pVector = &(pValue[j].Value);
296 else if (pValue[j].Name.equals( sPropIterationCount ) )
297 pCount = &(pValue[j].Value);
298 else if (pValue[j].Name.equals( sPropSize ) )
299 pSize = &(pValue[j].Value);
300 else if (pValue[j].Name.equals( sPropDigest ) )
301 pDigest = &(pValue[j].Value);
303 if (sPath.getLength() && hasByHierarchicalName ( sPath ) )
305 aAny = getByHierarchicalName( sPath );
306 uno::Reference < XUnoTunnel > xUnoTunnel;
307 aAny >>= xUnoTunnel;
308 sal_Int64 nTest=0;
309 if ((nTest = xUnoTunnel->getSomething(ZipPackageFolder::static_getImplementationId())) != 0)
311 pFolder = reinterpret_cast < ZipPackageFolder* > ( nTest );
312 pFolder->SetMediaType ( sMediaType );
313 pFolder->SetVersion ( sVersion );
315 else
317 pStream = reinterpret_cast < ZipPackageStream* > ( xUnoTunnel->getSomething(ZipPackageStream::static_getImplementationId()));
318 pStream->SetMediaType ( sMediaType );
320 if (pSalt && pVector && pCount && pSize)
322 Sequence < sal_uInt8 > aSequence;
323 sal_Int32 nCount = 0, nSize = 0;
324 pStream->SetToBeEncrypted ( sal_True );
326 *pSalt >>= aSequence;
327 pStream->setSalt ( aSequence );
329 *pVector >>= aSequence;
330 pStream->setInitialisationVector ( aSequence );
332 *pCount >>= nCount;
333 pStream->setIterationCount ( nCount );
335 *pSize >>= nSize;
336 pStream->setSize ( nSize );
338 if ( pDigest )
340 *pDigest >>= aSequence;
341 pStream->setDigest ( aSequence );
344 pStream->SetToBeCompressed ( sal_True );
345 pStream->SetToBeEncrypted ( sal_True );
346 pStream->SetIsEncrypted ( sal_True );
347 if ( !bHasEncryptedEntries && pStream->getName().compareToAscii ( "content.xml" ) == 0 )
348 bHasEncryptedEntries = sal_True;
354 bManifestParsed = sal_True;
356 else
357 VOS_ENSURE ( 0, "Couldn't get a ManifestReader!" ); // throw RuntimeException?
360 // now hide the manifest.xml file from user
361 xMetaInfFolder->removeByName( sManifest );
364 catch( Exception& )
366 if ( !bForceRecovery )
367 throw;
371 const OUString sMimetype ( RTL_CONSTASCII_USTRINGPARAM ( "mimetype" ) );
372 if ( xRootFolder->hasByName( sMimetype ) )
374 if ( !bManifestParsed )
376 // try to get mediatype from the "mimetype" stream
377 uno::Reference< lang::XUnoTunnel > xMimeTypeTunnel;
378 xRootFolder->getByName( sMimetype ) >>= xMimeTypeTunnel;
379 uno::Reference < io::XActiveDataSink > xMimeSink( xMimeTypeTunnel, UNO_QUERY );
380 if ( xMimeSink.is() )
382 uno::Reference< io::XInputStream > xMimeInStream = xMimeSink->getInputStream();
383 if ( xMimeInStream.is() )
385 // Mediatypes longer than 1024 symbols should not appear here
386 uno::Sequence< sal_Int8 > aData( 1024 );
387 sal_Int32 nRead = xMimeInStream->readBytes( aData, 1024 );
388 OSL_ENSURE( nRead == aData.getLength(), "Difference between reading result and data!\n" );
389 if ( nRead > aData.getLength() )
390 nRead = aData.getLength();
391 if ( nRead )
393 ::rtl::OUString aFallBack( (sal_Char*)aData.getConstArray(), nRead, RTL_TEXTENCODING_ASCII_US );
394 if ( aFallBack.compareToAscii( RTL_CONSTASCII_STRINGPARAM( "application/vnd." ) ) == 0 )
396 // accept only types that look similar to own mediatypes
397 pRootFolder->SetMediaType( aFallBack );
398 m_bMediaTypeFallbackUsed = sal_True;
405 xRootFolder->removeByName( sMimetype );
410 void ZipPackage::parseContentType()
412 if ( m_nFormat == OFOPXML_FORMAT )
414 const ::rtl::OUString aContentTypes( RTL_CONSTASCII_USTRINGPARAM ( "[Content_Types].xml" ) );
415 try {
416 // the content type must exist in OFOPXML format!
417 if ( !xRootFolder->hasByName( aContentTypes ) )
418 throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Wrong format!" ) ),
419 uno::Reference< uno::XInterface >() );
421 uno::Reference< lang::XUnoTunnel > xTunnel;
422 uno::Any aAny = xRootFolder->getByName( aContentTypes );
423 aAny >>= xTunnel;
424 uno::Reference < io::XActiveDataSink > xSink( xTunnel, UNO_QUERY );
425 if ( xSink.is() )
427 uno::Reference< io::XInputStream > xInStream = xSink->getInputStream();
428 if ( xInStream.is() )
430 sal_Int32 nInd = 0;
431 // here aContentTypeInfo[0] - Defaults, and aContentTypeInfo[1] - Overrides
432 uno::Sequence< uno::Sequence< beans::StringPair > > aContentTypeInfo =
433 ::comphelper::OFOPXMLHelper::ReadContentTypeSequence( xInStream, xFactory );
435 if ( aContentTypeInfo.getLength() != 2 )
436 throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
438 // set the implicit types fist
439 for ( nInd = 0; nInd < aContentTypeInfo[0].getLength(); nInd++ )
440 pRootFolder->setChildStreamsTypeByExtension( aContentTypeInfo[0][nInd] );
442 // now set the explicit types
443 for ( nInd = 0; nInd < aContentTypeInfo[1].getLength(); nInd++ )
445 ::rtl::OUString aPath;
446 if ( aContentTypeInfo[1][nInd].First.toChar() == (sal_Unicode)'/' )
447 aPath = aContentTypeInfo[1][nInd].First.copy( 1 );
448 else
449 aPath = aContentTypeInfo[1][nInd].First;
451 if ( aPath.getLength() && hasByHierarchicalName( aPath ) )
453 uno::Any aIterAny = getByHierarchicalName( aPath );
454 uno::Reference < lang::XUnoTunnel > xIterTunnel;
455 aIterAny >>= xIterTunnel;
456 sal_Int64 nTest = xIterTunnel->getSomething( ZipPackageStream::static_getImplementationId() );
457 if ( nTest != 0 )
459 // this is a package stream, in OFOPXML format only streams can have mediatype
460 ZipPackageStream *pStream = reinterpret_cast < ZipPackageStream* > ( nTest );
461 pStream->SetMediaType( aContentTypeInfo[1][nInd].Second );
468 xRootFolder->removeByName( aContentTypes );
470 catch( uno::Exception& )
472 if ( !bForceRecovery )
473 throw;
478 void ZipPackage::getZipFileContents()
480 auto_ptr < ZipEnumeration > pEnum ( pZipFile->entries() );
481 ZipPackageStream *pPkgStream;
482 ZipPackageFolder *pPkgFolder, *pCurrent;
483 OUString sTemp, sDirName;
484 sal_Int32 nOldIndex, nIndex, nStreamIndex;
485 FolderHash::iterator aIter;
487 while (pEnum->hasMoreElements())
489 nIndex = nOldIndex = 0;
490 pCurrent = pRootFolder;
491 const ZipEntry & rEntry = *pEnum->nextElement();
492 const OUString & rName = rEntry.sName;
494 nStreamIndex = rName.lastIndexOf ( '/' );
495 if ( nStreamIndex != -1 )
497 sDirName = rName.copy ( 0, nStreamIndex);
498 aIter = aRecent.find ( sDirName );
499 if ( aIter != aRecent.end() )
500 pCurrent = (*aIter).second;
503 if ( pCurrent == pRootFolder )
505 while ( (nIndex = rName.indexOf('/', nOldIndex) ) != -1 )
507 sTemp = rName.copy ( nOldIndex, nIndex - nOldIndex );
508 if (nIndex == nOldIndex)
509 break;
510 if ( !pCurrent->hasByName( sTemp ) )
512 pPkgFolder = new ZipPackageFolder( xFactory, m_nFormat, m_bAllowRemoveOnInsert );
513 pPkgFolder->setName( sTemp );
514 pPkgFolder->doSetParent( pCurrent, sal_True );
515 pCurrent = pPkgFolder;
517 else
518 pCurrent = pCurrent->doGetByName(sTemp).pFolder;
519 nOldIndex = nIndex+1;
521 if ( nStreamIndex != -1 && sDirName.getLength() )
522 aRecent [ sDirName ] = pCurrent;
524 if ( rName.getLength() -1 != nStreamIndex )
526 nStreamIndex++;
527 sTemp = rName.copy( nStreamIndex, rName.getLength() - nStreamIndex);
528 pPkgStream = new ZipPackageStream( *this, xFactory, m_bAllowRemoveOnInsert );
529 pPkgStream->SetPackageMember( sal_True );
530 pPkgStream->setZipEntryOnLoading( rEntry );
531 pPkgStream->setName( sTemp );
532 pPkgStream->doSetParent( pCurrent, sal_True );
536 if ( m_nFormat == PACKAGE_FORMAT )
537 parseManifest();
538 else if ( m_nFormat == OFOPXML_FORMAT )
539 parseContentType();
542 // XInitialization
543 void SAL_CALL ZipPackage::initialize( const Sequence< Any >& aArguments )
544 throw(Exception, RuntimeException)
546 RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "{ ZipPackage::initialize" );
547 sal_Bool bBadZipFile = sal_False, bHaveZipFile = sal_True;
548 uno::Reference< XProgressHandler > xProgressHandler;
549 beans::NamedValue aNamedValue;
551 if ( aArguments.getLength() )
553 for( int ind = 0; ind < aArguments.getLength(); ind++ )
555 OUString aParamUrl;
556 if ( (aArguments[ind] >>= aParamUrl))
558 eMode = e_IMode_URL;
561 sal_Int32 nParam = aParamUrl.indexOf( '?' );
562 if ( nParam >= 0 )
564 sURL = aParamUrl.copy( 0, nParam );
565 OUString aParam = aParamUrl.copy( nParam + 1 );
567 sal_Int32 nIndex = 0;
570 ::rtl::OUString aCommand = aParam.getToken( 0, '&', nIndex );
571 if ( aCommand.equals( OUString::createFromAscii( "repairpackage" ) ) )
573 bForceRecovery = sal_True;
574 break;
576 else if ( aCommand.equals( OUString::createFromAscii( "purezip" ) ) )
578 m_nFormat = ZIP_FORMAT;
579 pRootFolder->setPackageFormat_Impl( m_nFormat );
580 break;
582 else if ( aCommand.equals( OUString::createFromAscii( "ofopxml" ) ) )
584 m_nFormat = OFOPXML_FORMAT;
585 pRootFolder->setPackageFormat_Impl( m_nFormat );
586 break;
589 while ( nIndex >= 0 );
591 else
592 sURL = aParamUrl;
594 Content aContent ( sURL, uno::Reference < XCommandEnvironment >() );
595 Any aAny = aContent.getPropertyValue( OUString::createFromAscii( "Size" ) );
596 sal_uInt64 aSize = 0;
597 // kind of optimisation: treat empty files as nonexistent files
598 // and write to such files directly. Note that "Size" property is optional.
599 bool bHasSizeProperty = aAny >>= aSize;
600 if( !bHasSizeProperty || ( bHasSizeProperty && aSize ) )
602 uno::Reference < XActiveDataSink > xSink = new ZipPackageSink;
603 if (aContent.openStream ( xSink ) )
604 xContentStream = xSink->getInputStream();
606 else
607 bHaveZipFile = sal_False;
609 catch (com::sun::star::uno::Exception&)
611 // Exception derived from uno::Exception thrown. This probably
612 // means the file doesn't exist...we'll create it at
613 // commitChanges time
614 bHaveZipFile = sal_False;
617 else if ( (aArguments[ind] >>= xStream ) )
619 // a writable stream can implement both XStream & XInputStream
620 eMode = e_IMode_XStream;
621 xContentStream = xStream->getInputStream();
623 else if ( (aArguments[ind] >>= xContentStream) )
625 eMode = e_IMode_XInputStream;
627 else if ( ( aArguments[ind] >>= aNamedValue ) )
629 if ( aNamedValue.Name.equalsAscii( "RepairPackage" ) )
630 aNamedValue.Value >>= bForceRecovery;
631 else if ( aNamedValue.Name.equalsAscii( "PackageFormat" ) )
633 // setting this argument to true means Package format
634 // setting it to false means plain Zip format
636 sal_Bool bPackFormat = sal_True;
637 aNamedValue.Value >>= bPackFormat;
638 if ( !bPackFormat )
639 m_nFormat = ZIP_FORMAT;
641 pRootFolder->setPackageFormat_Impl( m_nFormat );
643 else if ( aNamedValue.Name.equalsAscii( "StorageFormat" ) )
645 ::rtl::OUString aFormatName;
646 aNamedValue.Value >>= aFormatName;
647 if ( aFormatName.equalsAscii( "PackageFormat" ) )
648 m_nFormat = PACKAGE_FORMAT;
649 else if ( aFormatName.equalsAscii( "ZipFormat" ) )
650 m_nFormat = ZIP_FORMAT;
651 else if ( aFormatName.equalsAscii( "OFOPXMLFormat" ) )
652 m_nFormat = OFOPXML_FORMAT;
653 else
654 throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 );
656 pRootFolder->setPackageFormat_Impl( m_nFormat );
658 else if ( aNamedValue.Name.equalsAscii( "AllowRemoveOnInsert" ) )
660 aNamedValue.Value >>= m_bAllowRemoveOnInsert;
661 pRootFolder->setRemoveOnInsertMode_Impl( m_bAllowRemoveOnInsert );
664 // for now the progress handler is not used, probably it will never be
665 // if ( aNamedValue.Name.equalsAscii( "ProgressHandler" )
667 else
669 // The URL is not acceptable
670 throw com::sun::star::uno::Exception ( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Bad arguments." ) ),
671 static_cast < ::cppu::OWeakObject * > ( this ) );
677 if (xContentStream.is())
679 // the stream must be seekable, if it is not it will be wrapped
680 xContentStream = ::comphelper::OSeekableInputWrapper::CheckSeekableCanWrap( xContentStream, xFactory );
681 xContentSeek = uno::Reference < XSeekable > ( xContentStream, UNO_QUERY );
682 if ( ! xContentSeek.is() )
683 throw com::sun::star::uno::Exception ( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "The package component _requires_ an XSeekable interface!" ) ),
684 static_cast < ::cppu::OWeakObject * > ( this ) );
686 if ( !xContentSeek->getLength() )
687 bHaveZipFile = sal_False;
689 else
690 bHaveZipFile = sal_False;
692 catch (com::sun::star::uno::Exception&)
694 // Exception derived from uno::Exception thrown. This probably
695 // means the file doesn't exist...we'll create it at
696 // commitChanges time
697 bHaveZipFile = sal_False;
699 if ( bHaveZipFile )
703 pZipFile = new ZipFile ( xContentStream, xFactory, sal_True, bForceRecovery, xProgressHandler );
704 getZipFileContents();
706 catch ( IOException & )
708 bBadZipFile = sal_True;
710 catch ( ZipException & )
712 bBadZipFile = sal_True;
714 catch ( Exception & )
716 if( pZipFile ) { delete pZipFile; pZipFile = NULL; }
717 throw;
720 if ( bBadZipFile )
722 // clean up the memory, and tell the UCB about the error
723 if( pZipFile ) { delete pZipFile; pZipFile = NULL; }
725 throw com::sun::star::packages::zip::ZipIOException (
726 OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Bad Zip File." ) ),
727 static_cast < ::cppu::OWeakObject * > ( this ) );
732 RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "} ZipPackage::initialize" );
735 Any SAL_CALL ZipPackage::getByHierarchicalName( const OUString& aName )
736 throw(NoSuchElementException, RuntimeException)
738 OUString sTemp, sDirName;
739 sal_Int32 nOldIndex, nIndex, nStreamIndex;
740 FolderHash::iterator aIter;
742 if ( (nIndex = aName.getLength() ) == 1 && *aName.getStr() == '/' )
743 return makeAny ( uno::Reference < XUnoTunnel > (pRootFolder) );
744 else
746 nStreamIndex = aName.lastIndexOf ( '/' );
747 bool bFolder = nStreamIndex == nIndex-1;
748 if ( nStreamIndex != -1 )
750 sDirName = aName.copy ( 0, nStreamIndex);
751 aIter = aRecent.find ( sDirName );
752 if ( aIter != aRecent.end() )
754 if ( bFolder )
756 sal_Int32 nDirIndex = aName.lastIndexOf ( '/', nStreamIndex );
757 sTemp = aName.copy ( nDirIndex == -1 ? 0 : nDirIndex+1, nStreamIndex-nDirIndex-1 );
758 if ( sTemp == (*aIter).second->getName() )
759 return makeAny ( uno::Reference < XUnoTunnel > ( (*aIter).second ) );
760 else
761 aRecent.erase ( aIter );
763 else
765 sTemp = aName.copy ( nStreamIndex + 1 );
766 if ( (*aIter).second->hasByName( sTemp ) )
767 return (*aIter).second->getByName( sTemp );
768 else
769 aRecent.erase( aIter );
773 else
775 if ( pRootFolder->hasByName ( aName ) )
776 return pRootFolder->getByName ( aName );
778 nOldIndex = 0;
779 ZipPackageFolder * pCurrent = pRootFolder;
780 ZipPackageFolder * pPrevious = NULL;
781 while ( ( nIndex = aName.indexOf('/', nOldIndex)) != -1)
783 sTemp = aName.copy (nOldIndex, nIndex - nOldIndex);
784 if ( nIndex == nOldIndex )
785 break;
786 if ( pCurrent->hasByName( sTemp ) )
788 pPrevious = pCurrent;
789 pCurrent = pCurrent->doGetByName(sTemp).pFolder;
791 else
792 throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
793 nOldIndex = nIndex+1;
795 if ( bFolder )
797 if (nStreamIndex != -1 )
798 aRecent[sDirName] = pPrevious;
799 return makeAny ( uno::Reference < XUnoTunnel > ( pCurrent ) );
801 else
803 sTemp = aName.copy( nOldIndex, aName.getLength() - nOldIndex);
804 if ( pCurrent->hasByName ( sTemp ) )
806 if (nStreamIndex != -1 )
807 aRecent[sDirName] = pCurrent;
808 return pCurrent->getByName( sTemp );
810 else
811 throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
816 sal_Bool SAL_CALL ZipPackage::hasByHierarchicalName( const OUString& aName )
817 throw(RuntimeException)
819 OUString sTemp, sDirName;
820 sal_Int32 nOldIndex, nIndex, nStreamIndex;
821 FolderHash::iterator aIter;
823 if ( (nIndex = aName.getLength() ) == 1 && *aName.getStr() == '/' )
824 return sal_True;
825 else
827 nStreamIndex = aName.lastIndexOf ( '/' );
828 bool bFolder = nStreamIndex == nIndex-1;
829 if ( nStreamIndex != -1 )
831 sDirName = aName.copy ( 0, nStreamIndex);
832 aIter = aRecent.find ( sDirName );
833 if ( aIter != aRecent.end() )
835 if ( bFolder )
837 sal_Int32 nDirIndex = aName.lastIndexOf ( '/', nStreamIndex );
838 sTemp = aName.copy ( nDirIndex == -1 ? 0 : nDirIndex+1, nStreamIndex-nDirIndex-1 );
839 if ( sTemp == (*aIter).second->getName() )
840 return sal_True;
841 else
842 aRecent.erase ( aIter );
844 else
846 sTemp = aName.copy ( nStreamIndex + 1 );
847 if ( (*aIter).second->hasByName( sTemp ) )
848 return sal_True;
849 else
850 aRecent.erase( aIter );
854 else
856 if ( pRootFolder->hasByName ( aName ) )
857 return sal_True;
859 ZipPackageFolder * pCurrent = pRootFolder;
860 ZipPackageFolder * pPrevious = NULL;
861 nOldIndex = 0;
862 while ( ( nIndex = aName.indexOf('/', nOldIndex)) != -1)
864 sTemp = aName.copy (nOldIndex, nIndex - nOldIndex);
865 if ( nIndex == nOldIndex )
866 break;
867 if ( pCurrent->hasByName( sTemp ) )
869 pPrevious = pCurrent;
870 pCurrent = pCurrent->doGetByName( sTemp ).pFolder;
872 else
873 return sal_False;
874 nOldIndex = nIndex+1;
876 if ( bFolder )
878 aRecent[sDirName] = pPrevious;
879 return sal_True;
881 else
883 sTemp = aName.copy( nOldIndex, aName.getLength() - nOldIndex);
885 if ( pCurrent->hasByName( sTemp ) )
887 aRecent[sDirName] = pCurrent;
888 return sal_True;
891 return sal_False;
895 // XSingleServiceFactory
896 uno::Reference< XInterface > SAL_CALL ZipPackage::createInstance( )
897 throw(Exception, RuntimeException)
899 uno::Reference < XInterface > xRef = *(new ZipPackageStream ( *this, xFactory, m_bAllowRemoveOnInsert ));
900 return xRef;
902 uno::Reference< XInterface > SAL_CALL ZipPackage::createInstanceWithArguments( const Sequence< Any >& aArguments )
903 throw(Exception, RuntimeException)
905 sal_Bool bArg = sal_False;
906 uno::Reference < XInterface > xRef;
907 if ( aArguments.getLength() )
908 aArguments[0] >>= bArg;
909 if (bArg)
910 xRef = *new ZipPackageFolder ( xFactory, m_nFormat, m_bAllowRemoveOnInsert );
911 else
912 xRef = *new ZipPackageStream ( *this, xFactory, m_bAllowRemoveOnInsert );
914 return xRef;
917 void ZipPackage::WriteMimetypeMagicFile( ZipOutputStream& aZipOut )
919 const OUString sMime ( RTL_CONSTASCII_USTRINGPARAM ( "mimetype" ) );
920 if (xRootFolder->hasByName( sMime ) )
921 xRootFolder->removeByName( sMime );
923 ZipEntry * pEntry = new ZipEntry;
924 sal_Int32 nBufferLength = pRootFolder->GetMediaType( ).getLength();
925 OString sMediaType = OUStringToOString( pRootFolder->GetMediaType(), RTL_TEXTENCODING_ASCII_US );
926 Sequence< sal_Int8 > aType( (sal_Int8*)sMediaType.getStr(),
927 nBufferLength );
930 pEntry->sName = sMime;
931 pEntry->nMethod = STORED;
932 pEntry->nSize = pEntry->nCompressedSize = nBufferLength;
933 pEntry->nTime = ZipOutputStream::getCurrentDosTime();
935 CRC32 aCRC32;
936 aCRC32.update( aType );
937 pEntry->nCrc = aCRC32.getValue();
941 vos::ORef < EncryptionData > xEmpty;
942 aZipOut.putNextEntry( *pEntry, xEmpty );
943 aZipOut.write( aType, 0, nBufferLength );
944 aZipOut.closeEntry();
946 catch ( ::com::sun::star::io::IOException & r )
948 VOS_ENSURE( 0, "Error adding mimetype to the ZipOutputStream" );
949 throw WrappedTargetException(
950 OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Error adding mimetype to the ZipOutputStream!" ) ),
951 static_cast < OWeakObject * > ( this ),
952 makeAny( r ) );
956 void ZipPackage::WriteManifest( ZipOutputStream& aZipOut, const vector< Sequence < PropertyValue > >& aManList )
958 // Write the manifest
959 uno::Reference < XOutputStream > xManOutStream;
960 OUString sManifestWriter( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.manifest.ManifestWriter" ) );
961 uno::Reference < XManifestWriter > xWriter ( xFactory->createInstance( sManifestWriter ), UNO_QUERY );
962 if ( xWriter.is() )
964 ZipEntry * pEntry = new ZipEntry;
965 ZipPackageBuffer *pBuffer = new ZipPackageBuffer( n_ConstBufferSize );
966 xManOutStream = uno::Reference < XOutputStream > (*pBuffer, UNO_QUERY);
968 pEntry->sName = OUString( RTL_CONSTASCII_USTRINGPARAM ( "META-INF/manifest.xml") );
969 pEntry->nMethod = DEFLATED;
970 pEntry->nCrc = pEntry->nSize = pEntry->nCompressedSize = -1;
971 pEntry->nTime = ZipOutputStream::getCurrentDosTime();
973 // Convert vector into a Sequence
974 Sequence < Sequence < PropertyValue > > aManifestSequence ( aManList.size() );
975 Sequence < PropertyValue > * pSequence = aManifestSequence.getArray();
976 for (vector < Sequence < PropertyValue > >::const_iterator aIter = aManList.begin(), aEnd = aManList.end();
977 aIter != aEnd;
978 aIter++, pSequence++)
979 *pSequence= (*aIter);
980 xWriter->writeManifestSequence ( xManOutStream, aManifestSequence );
982 sal_Int32 nBufferLength = static_cast < sal_Int32 > ( pBuffer->getPosition() );
983 pBuffer->realloc( nBufferLength );
985 // the manifest.xml is never encrypted - so pass an empty reference
986 vos::ORef < EncryptionData > xEmpty;
987 aZipOut.putNextEntry( *pEntry, xEmpty );
988 aZipOut.write( pBuffer->getSequence(), 0, nBufferLength );
989 aZipOut.closeEntry();
991 else
993 VOS_ENSURE ( 0, "Couldn't get a ManifestWriter!" );
994 IOException aException;
995 throw WrappedTargetException(
996 OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Couldn't get a ManifestWriter!" ) ),
997 static_cast < OWeakObject * > ( this ),
998 makeAny( aException ) );
1002 void ZipPackage::WriteContentTypes( ZipOutputStream& aZipOut, const vector< Sequence < PropertyValue > >& aManList )
1004 const OUString sFullPath ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) );
1005 const OUString sMediaType ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) );
1007 ZipEntry* pEntry = new ZipEntry;
1008 ZipPackageBuffer *pBuffer = new ZipPackageBuffer( n_ConstBufferSize );
1009 uno::Reference< io::XOutputStream > xConTypeOutStream( *pBuffer, UNO_QUERY );
1011 pEntry->sName = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "[Content_Types].xml") );
1012 pEntry->nMethod = DEFLATED;
1013 pEntry->nCrc = pEntry->nSize = pEntry->nCompressedSize = -1;
1014 pEntry->nTime = ZipOutputStream::getCurrentDosTime();
1016 // Convert vector into a Sequence
1017 // TODO/LATER: use Defaulst entries in future
1018 uno::Sequence< beans::StringPair > aDefaultsSequence;
1019 uno::Sequence< beans::StringPair > aOverridesSequence( aManList.size() );
1020 sal_Int32 nSeqLength = 0;
1021 for ( vector< uno::Sequence< beans::PropertyValue > >::const_iterator aIter = aManList.begin(),
1022 aEnd = aManList.end();
1023 aIter != aEnd;
1024 aIter++)
1026 ::rtl::OUString aPath;
1027 ::rtl::OUString aType;
1028 OSL_ENSURE( (*aIter)[PKG_MNFST_MEDIATYPE].Name.equals( sMediaType ) && (*aIter)[PKG_MNFST_FULLPATH].Name.equals( sFullPath ),
1029 "The mediatype sequence format is wrong!\n" );
1030 (*aIter)[PKG_MNFST_MEDIATYPE].Value >>= aType;
1031 if ( aType.getLength() )
1033 // only nonempty type makes sence here
1034 nSeqLength++;
1035 (*aIter)[PKG_MNFST_FULLPATH].Value >>= aPath;
1036 aOverridesSequence[nSeqLength-1].First = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/" ) ) + aPath;
1037 aOverridesSequence[nSeqLength-1].Second = aType;
1040 aOverridesSequence.realloc( nSeqLength );
1042 ::comphelper::OFOPXMLHelper::WriteContentSequence(
1043 xConTypeOutStream, aDefaultsSequence, aOverridesSequence, xFactory );
1045 sal_Int32 nBufferLength = static_cast < sal_Int32 > ( pBuffer->getPosition() );
1046 pBuffer->realloc( nBufferLength );
1048 // there is no encryption in this format currently
1049 vos::ORef < EncryptionData > xEmpty;
1050 aZipOut.putNextEntry( *pEntry, xEmpty );
1051 aZipOut.write( pBuffer->getSequence(), 0, nBufferLength );
1052 aZipOut.closeEntry();
1055 void ZipPackage::ConnectTo( const uno::Reference< io::XInputStream >& xInStream )
1057 xContentSeek.set( xInStream, uno::UNO_QUERY_THROW );
1058 xContentStream = xInStream;
1060 // seek back to the beginning of the temp file so we can read segments from it
1061 xContentSeek->seek( 0 );
1062 if ( pZipFile )
1063 pZipFile->setInputStream( xContentStream );
1064 else
1065 pZipFile = new ZipFile ( xContentStream, xFactory, sal_False );
1068 uno::Reference< io::XInputStream > ZipPackage::writeTempFile()
1070 // In case the target local file does not exist or empty
1071 // write directly to it otherwize create a temporary file to write to.
1072 // If a temporary file is created it is returned back by the method.
1073 // If the data written directly, xComponentStream will be switched here
1075 sal_Bool bUseTemp = sal_True;
1076 uno::Reference < io::XInputStream > xResult;
1077 uno::Reference < io::XInputStream > xTempIn;
1079 uno::Reference < io::XOutputStream > xTempOut;
1080 uno::Reference< io::XActiveDataStreamer > xSink;
1082 if ( eMode == e_IMode_URL && !pZipFile && isLocalFile_Impl( sURL ) )
1084 xSink = openOriginalForOutput();
1085 if( xSink.is() )
1087 uno::Reference< io::XStream > xStr = xSink->getStream();
1088 if( xStr.is() )
1090 xTempOut = xStr->getOutputStream();
1091 if( xTempOut.is() )
1092 bUseTemp = sal_False;
1096 else if ( eMode == e_IMode_XStream && !pZipFile )
1098 // write directly to an empty stream
1099 xTempOut = xStream->getOutputStream();
1100 if( xTempOut.is() )
1101 bUseTemp = sal_False;
1104 if( bUseTemp )
1106 // create temporary file
1107 const OUString sServiceName ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.TempFile" ) );
1108 uno::Reference < io::XStream > xTempFile( xFactory->createInstance ( sServiceName ), UNO_QUERY_THROW );
1109 xTempOut.set( xTempFile->getOutputStream(), UNO_SET_THROW );
1110 xTempIn.set( xTempFile->getInputStream(), UNO_SET_THROW );
1113 // Hand it to the ZipOutputStream:
1114 ZipOutputStream aZipOut ( xTempOut );
1115 aZipOut.setMethod(DEFLATED);
1116 aZipOut.setLevel(DEFAULT_COMPRESSION);
1120 if ( m_nFormat == PACKAGE_FORMAT )
1122 // Remove the old manifest.xml file as the
1123 // manifest will be re-generated and the
1124 // META-INF directory implicitly created if does not exist
1125 const OUString sMeta ( RTL_CONSTASCII_USTRINGPARAM ( "META-INF" ) );
1127 if ( xRootFolder->hasByName( sMeta ) )
1129 const OUString sManifest (RTL_CONSTASCII_USTRINGPARAM( "manifest.xml") );
1131 uno::Reference< XUnoTunnel > xTunnel;
1132 Any aAny = xRootFolder->getByName( sMeta );
1133 aAny >>= xTunnel;
1134 uno::Reference< XNameContainer > xMetaInfFolder( xTunnel, UNO_QUERY );
1135 if ( xMetaInfFolder.is() && xMetaInfFolder->hasByName( sManifest ) )
1136 xMetaInfFolder->removeByName( sManifest );
1139 // Write a magic file with mimetype
1140 WriteMimetypeMagicFile( aZipOut );
1142 else if ( m_nFormat == OFOPXML_FORMAT )
1144 // Remove the old [Content_Types].xml file as the
1145 // file will be re-generated
1147 const ::rtl::OUString aContentTypes( RTL_CONSTASCII_USTRINGPARAM ( "[Content_Types].xml" ) );
1149 if ( xRootFolder->hasByName( aContentTypes ) )
1150 xRootFolder->removeByName( aContentTypes );
1153 // Create a vector to store data for the manifest.xml file
1154 vector < Sequence < PropertyValue > > aManList;
1156 const OUString sMediaType ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) );
1157 const OUString sVersion ( RTL_CONSTASCII_USTRINGPARAM ( "Version" ) );
1158 const OUString sFullPath ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) );
1160 if ( m_nFormat == PACKAGE_FORMAT )
1162 Sequence < PropertyValue > aPropSeq ( PKG_SIZE_NOENCR_MNFST );
1163 aPropSeq [PKG_MNFST_MEDIATYPE].Name = sMediaType;
1164 aPropSeq [PKG_MNFST_MEDIATYPE].Value <<= pRootFolder->GetMediaType( );
1165 aPropSeq [PKG_MNFST_VERSION].Name = sVersion;
1166 aPropSeq [PKG_MNFST_VERSION].Value <<= pRootFolder->GetVersion( );
1167 aPropSeq [PKG_MNFST_FULLPATH].Name = sFullPath;
1168 aPropSeq [PKG_MNFST_FULLPATH].Value <<= OUString ( RTL_CONSTASCII_USTRINGPARAM ( "/" ) );
1170 aManList.push_back( aPropSeq );
1173 // Get a random number generator and seed it with current timestamp
1174 // This will be used to generate random salt and initialisation vectors
1175 // for encrypted streams
1176 TimeValue aTime;
1177 osl_getSystemTime( &aTime );
1178 rtlRandomPool aRandomPool = rtl_random_createPool ();
1179 rtl_random_addBytes ( aRandomPool, &aTime, 8 );
1182 // call saveContents (it will recursively save sub-directories
1183 OUString aEmptyString;
1184 pRootFolder->saveContents( aEmptyString, aManList, aZipOut, aEncryptionKey, aRandomPool );
1186 // Clean up random pool memory
1187 rtl_random_destroyPool ( aRandomPool );
1189 if( bUseManifest && m_nFormat == PACKAGE_FORMAT )
1191 WriteManifest( aZipOut, aManList );
1193 else if( m_nFormat == OFOPXML_FORMAT )
1195 WriteContentTypes( aZipOut, aManList );
1198 aZipOut.finish();
1200 if( bUseTemp )
1201 xResult = xTempIn;
1203 // Update our References to point to the new temp file
1204 if( !bUseTemp )
1206 // the case when the original contents were written directly
1207 xTempOut->flush();
1209 // in case the stream is based on a file it will implement the following interface
1210 // the call should be used to be sure that the contents are written to the file system
1211 uno::Reference< io::XAsyncOutputMonitor > asyncOutputMonitor( xTempOut, uno::UNO_QUERY );
1212 if ( asyncOutputMonitor.is() )
1213 asyncOutputMonitor->waitForCompletion();
1215 // no need to postpone switching to the new stream since the target was written directly
1216 uno::Reference< io::XInputStream > xNewStream;
1217 if ( eMode == e_IMode_URL )
1218 xNewStream = xSink->getStream()->getInputStream();
1219 else if ( eMode == e_IMode_XStream && xStream.is() )
1220 xNewStream = xStream->getInputStream();
1222 if ( xNewStream.is() )
1223 ConnectTo( xNewStream );
1226 catch ( uno::Exception& )
1228 if( bUseTemp )
1230 // no information loss appeares, thus no special handling is required
1231 uno::Any aCaught( ::cppu::getCaughtException() );
1233 // it is allowed to throw WrappedTargetException
1234 WrappedTargetException aException;
1235 if ( aCaught >>= aException )
1236 throw aException;
1238 throw WrappedTargetException(
1239 OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Problem writing the original content!" ) ),
1240 static_cast < OWeakObject * > ( this ),
1241 aCaught );
1243 else
1245 // the document is written directly, although it was empty it is important to notify that the writing has failed
1246 // TODO/LATER: let the package be able to recover in this situation
1247 ::rtl::OUString aErrTxt( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is unusable!" ) );
1248 embed::UseBackupException aException( aErrTxt, uno::Reference< uno::XInterface >(), ::rtl::OUString() );
1249 throw WrappedTargetException( aErrTxt,
1250 static_cast < OWeakObject * > ( this ),
1251 makeAny ( aException ) );
1255 return xResult;
1258 uno::Reference< XActiveDataStreamer > ZipPackage::openOriginalForOutput()
1260 // open and truncate the original file
1261 Content aOriginalContent (sURL, uno::Reference < XCommandEnvironment >() );
1262 uno::Reference< XActiveDataStreamer > xSink = new ActiveDataStreamer;
1264 if ( eMode == e_IMode_URL )
1268 sal_Bool bTruncSuccess = sal_False;
1272 Exception aDetect;
1273 sal_Int64 aSize = 0;
1274 Any aAny = aOriginalContent.setPropertyValue( OUString::createFromAscii( "Size" ), makeAny( aSize ) );
1275 if( !( aAny >>= aDetect ) )
1276 bTruncSuccess = sal_True;
1278 catch( Exception& )
1282 if( !bTruncSuccess )
1284 // the file is not accessible
1285 // just try to write an empty stream to it
1287 uno::Reference< XInputStream > xTempIn = new DummyInputStream; //uno::Reference< XInputStream >( xTempOut, UNO_QUERY );
1288 aOriginalContent.writeStream( xTempIn , sal_True );
1291 OpenCommandArgument2 aArg;
1292 aArg.Mode = OpenMode::DOCUMENT;
1293 aArg.Priority = 0; // unused
1294 aArg.Sink = xSink;
1295 aArg.Properties = Sequence< Property >( 0 ); // unused
1297 aOriginalContent.executeCommand( OUString::createFromAscii( "open" ), makeAny( aArg ) );
1299 catch( Exception& )
1301 // seems to be nonlocal file
1302 // temporary file mechanics should be used
1306 return xSink;
1309 // XChangesBatch
1310 void SAL_CALL ZipPackage::commitChanges()
1311 throw(WrappedTargetException, RuntimeException)
1313 // lock the component for the time of commiting
1314 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
1316 if ( eMode == e_IMode_XInputStream )
1318 IOException aException;
1319 throw WrappedTargetException( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is read only!" ) ),
1320 static_cast < OWeakObject * > ( this ), makeAny ( aException ) );
1323 RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "{ ZipPackage::commitChanges" );
1325 // first the writeTempFile is called, if it returns a stream the stream should be written to the target
1326 // if no stream was returned, the file was written directly, nothing should be done
1328 uno::Reference< io::XInputStream > xTempInStream = writeTempFile();
1329 if ( xTempInStream.is() )
1331 uno::Reference< io::XSeekable > xTempSeek( xTempInStream, uno::UNO_QUERY_THROW );
1333 // switch to the new temporary stream only after the transfer
1334 PostinitializationGuard( xTempInStream, *this );
1336 if ( eMode == e_IMode_XStream )
1338 // First truncate our output stream
1339 uno::Reference < XOutputStream > xOutputStream;
1341 // preparation for copy step
1344 xTempSeek->seek( 0 );
1346 xOutputStream = xStream->getOutputStream();
1347 uno::Reference < XTruncate > xTruncate ( xOutputStream, UNO_QUERY );
1348 if ( !xTruncate.is() )
1349 throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1351 // after successful truncation the original file contents are already lost
1352 xTruncate->truncate();
1354 catch( uno::Exception& r )
1356 throw WrappedTargetException( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is read only!" ) ),
1357 static_cast < OWeakObject * > ( this ), makeAny ( r ) );
1362 // then copy the contents of the tempfile to our output stream
1363 ::comphelper::OStorageHelper::CopyInputToOutput( xTempInStream, xOutputStream );
1364 xOutputStream->flush();
1365 uno::Reference< io::XAsyncOutputMonitor > asyncOutputMonitor(
1366 xOutputStream, uno::UNO_QUERY);
1367 if (asyncOutputMonitor.is()) {
1368 asyncOutputMonitor->waitForCompletion();
1371 catch( uno::Exception& )
1373 // if anything goes wrong in this block the target file becomes corrupted
1374 // so an exception should be thrown as a notification about it
1375 // and the package must disconnect from the stream
1376 DisconnectFromTargetAndThrowException_Impl( xTempInStream );
1379 else if ( eMode == e_IMode_URL )
1381 uno::Reference< XOutputStream > aOrigFileStream;
1382 sal_Bool bCanBeCorrupted = sal_False;
1384 if( isLocalFile_Impl( sURL ) )
1386 // write directly in case of local file
1387 uno::Reference< ::com::sun::star::ucb::XSimpleFileAccess > xSimpleAccess(
1388 xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ),
1389 uno::UNO_QUERY );
1390 OSL_ENSURE( xSimpleAccess.is(), "Can't instatiate SimpleFileAccess service!\n" );
1391 uno::Reference< io::XTruncate > xOrigTruncate;
1392 if ( xSimpleAccess.is() )
1396 aOrigFileStream = xSimpleAccess->openFileWrite( sURL );
1397 xOrigTruncate = uno::Reference< io::XTruncate >( aOrigFileStream, uno::UNO_QUERY_THROW );
1398 // after successful truncation the file is already corrupted
1399 xOrigTruncate->truncate();
1401 catch( uno::Exception& )
1405 if( xOrigTruncate.is() )
1409 ::comphelper::OStorageHelper::CopyInputToOutput( xTempInStream, aOrigFileStream );
1410 aOrigFileStream->closeOutput();
1412 catch( uno::Exception& )
1414 try {
1415 aOrigFileStream->closeOutput();
1416 } catch ( uno::Exception& ) {}
1418 aOrigFileStream = uno::Reference< XOutputStream >();
1419 // the original file can already be corrupted
1420 bCanBeCorrupted = sal_True;
1425 if( !aOrigFileStream.is() )
1429 uno::Reference < XPropertySet > xPropSet ( xTempInStream, UNO_QUERY );
1430 OSL_ENSURE( xPropSet.is(), "This is a temporary file that must implement XPropertySet!\n" );
1431 if ( !xPropSet.is() )
1432 throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1434 OUString sTargetFolder = sURL.copy ( 0, sURL.lastIndexOf ( static_cast < sal_Unicode > ( '/' ) ) );
1435 Content aContent ( sTargetFolder, uno::Reference < XCommandEnvironment > () );
1437 OUString sTempURL;
1438 Any aAny = xPropSet->getPropertyValue ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Uri" ) ) );
1439 aAny >>= sTempURL;
1441 TransferInfo aInfo;
1442 aInfo.NameClash = NameClash::OVERWRITE;
1443 aInfo.MoveData = sal_False;
1444 aInfo.SourceURL = sTempURL;
1445 aInfo.NewTitle = rtl::Uri::decode ( sURL.copy ( 1 + sURL.lastIndexOf ( static_cast < sal_Unicode > ( '/' ) ) ),
1446 rtl_UriDecodeWithCharset,
1447 RTL_TEXTENCODING_UTF8 );
1448 aAny <<= aInfo;
1450 // if the file is still not corrupted, it can become after the next step
1451 aContent.executeCommand ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "transfer" ) ), aAny );
1453 catch (::com::sun::star::uno::Exception& r)
1455 if ( bCanBeCorrupted )
1456 DisconnectFromTargetAndThrowException_Impl( xTempInStream );
1458 throw WrappedTargetException(
1459 OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package may be read only!" ) ),
1460 static_cast < OWeakObject * > ( this ),
1461 makeAny ( r ) );
1467 // after successful storing it can be set to false
1468 m_bMediaTypeFallbackUsed = sal_False;
1470 RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "} ZipPackage::commitChanges" );
1473 void ZipPackage::DisconnectFromTargetAndThrowException_Impl( const uno::Reference< io::XInputStream >& xTempStream )
1475 xStream = uno::Reference< io::XStream >( xTempStream, uno::UNO_QUERY );
1476 if ( xStream.is() )
1477 eMode = e_IMode_XStream;
1478 else
1479 eMode = e_IMode_XInputStream;
1481 ::rtl::OUString aTempURL;
1482 try {
1483 uno::Reference< beans::XPropertySet > xTempFile( xTempStream, uno::UNO_QUERY_THROW );
1484 uno::Any aUrl = xTempFile->getPropertyValue( ::rtl::OUString::createFromAscii( "Uri" ) );
1485 aUrl >>= aTempURL;
1486 xTempFile->setPropertyValue( ::rtl::OUString::createFromAscii( "RemoveFile" ),
1487 uno::makeAny( sal_False ) );
1489 catch ( uno::Exception& )
1491 OSL_ENSURE( sal_False, "These calls are pretty simple, they should not fail!\n" );
1494 ::rtl::OUString aErrTxt( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is read only!" ) );
1495 embed::UseBackupException aException( aErrTxt, uno::Reference< uno::XInterface >(), aTempURL );
1496 throw WrappedTargetException( aErrTxt,
1497 static_cast < OWeakObject * > ( this ),
1498 makeAny ( aException ) );
1501 sal_Bool SAL_CALL ZipPackage::hasPendingChanges( )
1502 throw(RuntimeException)
1504 return sal_False;
1506 Sequence< ElementChange > SAL_CALL ZipPackage::getPendingChanges( )
1507 throw(RuntimeException)
1509 return Sequence < ElementChange > ();
1513 * Function to create a new component instance; is needed by factory helper implementation.
1514 * @param xMgr service manager to if the components needs other component instances
1516 uno::Reference < XInterface >SAL_CALL ZipPackage_createInstance(
1517 const uno::Reference< XMultiServiceFactory > & xMgr )
1519 return uno::Reference< XInterface >( *new ZipPackage(xMgr) );
1522 OUString ZipPackage::static_getImplementationName()
1524 return OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.comp.ZipPackage" ) );
1527 Sequence< OUString > ZipPackage::static_getSupportedServiceNames()
1529 Sequence< OUString > aNames(1);
1530 aNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.Package" ) );
1531 return aNames;
1533 sal_Bool SAL_CALL ZipPackage::static_supportsService( OUString const & rServiceName )
1535 return rServiceName == getSupportedServiceNames()[0];
1538 OUString ZipPackage::getImplementationName()
1539 throw (RuntimeException)
1541 return static_getImplementationName();
1544 Sequence< OUString > ZipPackage::getSupportedServiceNames()
1545 throw (RuntimeException)
1547 return static_getSupportedServiceNames();
1549 sal_Bool SAL_CALL ZipPackage::supportsService( OUString const & rServiceName )
1550 throw (RuntimeException)
1552 return static_supportsService ( rServiceName );
1554 uno::Reference < XSingleServiceFactory > ZipPackage::createServiceFactory( uno::Reference < XMultiServiceFactory > const & rServiceFactory )
1556 return cppu::createSingleFactory (rServiceFactory,
1557 static_getImplementationName(),
1558 ZipPackage_createInstance,
1559 static_getSupportedServiceNames());
1562 // XUnoTunnel
1563 Sequence< sal_Int8 > ZipPackage::getUnoTunnelImplementationId( void )
1564 throw (RuntimeException)
1566 static ::cppu::OImplementationId * pId = 0;
1567 if (! pId)
1569 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
1570 if (! pId)
1572 static ::cppu::OImplementationId aId;
1573 pId = &aId;
1576 return pId->getImplementationId();
1579 sal_Int64 SAL_CALL ZipPackage::getSomething( const Sequence< sal_Int8 >& aIdentifier )
1580 throw(RuntimeException)
1582 if (aIdentifier.getLength() == 16 && 0 == rtl_compareMemory(getUnoTunnelImplementationId().getConstArray(), aIdentifier.getConstArray(), 16 ) )
1583 return reinterpret_cast < sal_Int64 > ( this );
1584 return 0;
1587 uno::Reference< XPropertySetInfo > SAL_CALL ZipPackage::getPropertySetInfo( )
1588 throw(RuntimeException)
1590 return uno::Reference < XPropertySetInfo > ();
1592 void SAL_CALL ZipPackage::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
1593 throw(UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
1595 if ( m_nFormat != PACKAGE_FORMAT )
1596 throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1598 if (aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("HasEncryptedEntries") )
1599 ||aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("MediaTypeFallbackUsed") ) )
1600 throw PropertyVetoException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1601 else if (aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("EncryptionKey") ) )
1603 if (!( aValue >>= aEncryptionKey ) )
1604 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 2 );
1606 else if (aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("UseManifest") ) )
1608 if (!( aValue >>= bUseManifest ) )
1609 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 2 );
1611 else
1612 throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1614 Any SAL_CALL ZipPackage::getPropertyValue( const OUString& PropertyName )
1615 throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
1617 // TODO/LATER: Activate the check when zip-ucp is ready
1618 // if ( m_nFormat != PACKAGE_FORMAT )
1619 // throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1621 Any aAny;
1622 if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "EncryptionKey" ) ) )
1624 aAny <<= aEncryptionKey;
1625 return aAny;
1627 else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "HasEncryptedEntries" ) ) )
1629 aAny <<= bHasEncryptedEntries;
1630 return aAny;
1632 else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "UseManifest" ) ) )
1634 aAny <<= bUseManifest;
1635 return aAny;
1637 else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "MediaTypeFallbackUsed" ) ) )
1639 aAny <<= m_bMediaTypeFallbackUsed;
1640 return aAny;
1642 throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1644 void SAL_CALL ZipPackage::addPropertyChangeListener( const OUString& /*aPropertyName*/, const uno::Reference< XPropertyChangeListener >& /*xListener*/ )
1645 throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
1648 void SAL_CALL ZipPackage::removePropertyChangeListener( const OUString& /*aPropertyName*/, const uno::Reference< XPropertyChangeListener >& /*aListener*/ )
1649 throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
1652 void SAL_CALL ZipPackage::addVetoableChangeListener( const OUString& /*PropertyName*/, const uno::Reference< XVetoableChangeListener >& /*aListener*/ )
1653 throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
1656 void SAL_CALL ZipPackage::removeVetoableChangeListener( const OUString& /*PropertyName*/, const uno::Reference< XVetoableChangeListener >& /*aListener*/ )
1657 throw(UnknownPropertyException, WrappedTargetException, RuntimeException)