Update ooo320-m1
[ooovba.git] / package / source / zippackage / ZipPackage.cxx
blob494c3116f1eaf22ec8dcf9c5488a7531e596eeae
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 , m_bHasEncryptedEntries ( sal_False )
203 , m_bHasNonEncryptedEntries ( sal_False )
204 , m_bUseManifest ( sal_True )
205 , m_bForceRecovery ( sal_False )
206 , m_bMediaTypeFallbackUsed ( sal_False )
207 , m_nFormat( PACKAGE_FORMAT ) // package is the default format
208 , m_bAllowRemoveOnInsert( sal_True )
209 , m_eMode ( e_IMode_None )
210 , m_xFactory( xNewFactory )
211 , m_pRootFolder( NULL )
212 , m_pZipFile( NULL )
214 m_xRootFolder = m_pRootFolder = new ZipPackageFolder( m_xFactory, m_nFormat, m_bAllowRemoveOnInsert );
217 ZipPackage::~ZipPackage( void )
219 delete m_pZipFile;
221 // All folders and streams contain pointers to their parents, when a parent diappeares
222 // it should disconnect all the children from itself during destruction automatically.
223 // So there is no need in explicit m_pRootFolder->releaseUpwardRef() call here any more
224 // since m_pRootFolder has no parent and cleaning of it's children will be done automatically
225 // during m_pRootFolder dieing by refcount.
227 #if 0
228 // As all folders and streams contain references to their parents,
229 // we must remove these references so that they will be deleted when
230 // the hash_map of the root folder is cleared, releasing all subfolders
231 // and substreams which in turn release theirs, etc. When m_xRootFolder is
232 // released when this destructor completes, the folder tree should be
233 // deleted fully (and automagically).
235 m_pRootFolder->releaseUpwardRef();
236 #endif
239 void ZipPackage::parseManifest()
241 if ( m_nFormat == PACKAGE_FORMAT )
243 sal_Bool bManifestParsed = sal_False;
244 const OUString sMeta ( RTL_CONSTASCII_USTRINGPARAM ( "META-INF" ) );
245 if ( m_xRootFolder->hasByName( sMeta ) )
247 const OUString sManifest (RTL_CONSTASCII_USTRINGPARAM( "manifest.xml") );
249 try {
250 uno::Reference< XUnoTunnel > xTunnel;
251 Any aAny = m_xRootFolder->getByName( sMeta );
252 aAny >>= xTunnel;
253 uno::Reference< XNameContainer > xMetaInfFolder( xTunnel, UNO_QUERY );
254 if ( xMetaInfFolder.is() && xMetaInfFolder->hasByName( sManifest ) )
256 aAny = xMetaInfFolder->getByName( sManifest );
257 aAny >>= xTunnel;
258 uno::Reference < XActiveDataSink > xSink (xTunnel, UNO_QUERY);
259 if (xSink.is())
261 OUString sManifestReader ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.manifest.ManifestReader" ) );
262 uno::Reference < XManifestReader > xReader (m_xFactory->createInstance( sManifestReader ), UNO_QUERY );
263 if ( xReader.is() )
265 const OUString sPropFullPath ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) );
266 const OUString sPropVersion ( RTL_CONSTASCII_USTRINGPARAM ( "Version" ) );
267 const OUString sPropMediaType ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) );
268 const OUString sPropInitialisationVector ( RTL_CONSTASCII_USTRINGPARAM ( "InitialisationVector" ) );
269 const OUString sPropSalt ( RTL_CONSTASCII_USTRINGPARAM ( "Salt" ) );
270 const OUString sPropIterationCount ( RTL_CONSTASCII_USTRINGPARAM ( "IterationCount" ) );
271 const OUString sPropSize ( RTL_CONSTASCII_USTRINGPARAM ( "Size" ) );
272 const OUString sPropDigest ( RTL_CONSTASCII_USTRINGPARAM ( "Digest" ) );
274 Sequence < Sequence < PropertyValue > > aManifestSequence = xReader->readManifestSequence ( xSink->getInputStream() );
275 sal_Int32 nLength = aManifestSequence.getLength();
276 const Sequence < PropertyValue > *pSequence = aManifestSequence.getConstArray();
277 ZipPackageStream *pStream = NULL;
278 ZipPackageFolder *pFolder = NULL;
280 for (sal_Int32 i = 0; i < nLength ; i++, pSequence++)
282 OUString sPath, sMediaType, sVersion;
283 const PropertyValue *pValue = pSequence->getConstArray();
284 const Any *pSalt = NULL, *pVector = NULL, *pCount = NULL, *pSize = NULL, *pDigest = NULL;
285 for (sal_Int32 j = 0, nNum = pSequence->getLength(); j < nNum; j++ )
287 if (pValue[j].Name.equals( sPropFullPath ) )
288 pValue[j].Value >>= sPath;
289 else if (pValue[j].Name.equals( sPropVersion ) )
290 pValue[j].Value >>= sVersion;
291 else if (pValue[j].Name.equals( sPropMediaType ) )
292 pValue[j].Value >>= sMediaType;
293 else if (pValue[j].Name.equals( sPropSalt ) )
294 pSalt = &(pValue[j].Value);
295 else if (pValue[j].Name.equals( sPropInitialisationVector ) )
296 pVector = &(pValue[j].Value);
297 else if (pValue[j].Name.equals( sPropIterationCount ) )
298 pCount = &(pValue[j].Value);
299 else if (pValue[j].Name.equals( sPropSize ) )
300 pSize = &(pValue[j].Value);
301 else if (pValue[j].Name.equals( sPropDigest ) )
302 pDigest = &(pValue[j].Value);
305 if (sPath.getLength() && hasByHierarchicalName ( sPath ) )
307 aAny = getByHierarchicalName( sPath );
308 uno::Reference < XUnoTunnel > xUnoTunnel;
309 aAny >>= xUnoTunnel;
310 sal_Int64 nTest=0;
311 if ((nTest = xUnoTunnel->getSomething(ZipPackageFolder::static_getImplementationId())) != 0)
313 pFolder = reinterpret_cast < ZipPackageFolder* > ( nTest );
314 pFolder->SetMediaType ( sMediaType );
315 pFolder->SetVersion ( sVersion );
317 else
319 pStream = reinterpret_cast < ZipPackageStream* > ( xUnoTunnel->getSomething(ZipPackageStream::static_getImplementationId()));
320 pStream->SetMediaType ( sMediaType );
321 pStream->SetFromManifest( sal_True );
323 if (pSalt && pVector && pCount && pSize)
325 Sequence < sal_uInt8 > aSequence;
326 sal_Int32 nCount = 0, nSize = 0;
327 pStream->SetToBeEncrypted ( sal_True );
329 *pSalt >>= aSequence;
330 pStream->setSalt ( aSequence );
332 *pVector >>= aSequence;
333 pStream->setInitialisationVector ( aSequence );
335 *pCount >>= nCount;
336 pStream->setIterationCount ( nCount );
338 *pSize >>= nSize;
339 pStream->setSize ( nSize );
341 if ( pDigest )
343 *pDigest >>= aSequence;
344 pStream->setDigest ( aSequence );
347 pStream->SetToBeCompressed ( sal_True );
348 pStream->SetToBeEncrypted ( sal_True );
349 pStream->SetIsEncrypted ( sal_True );
350 if ( !m_bHasEncryptedEntries
351 && pStream->getName().equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "content.xml" ) ) ) )
352 m_bHasEncryptedEntries = sal_True;
354 else
355 m_bHasNonEncryptedEntries = sal_True;
360 bManifestParsed = sal_True;
362 else
363 throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "No manifes parser!" ) ), uno::Reference< uno::XInterface >() );
366 // now hide the manifest.xml file from user
367 xMetaInfFolder->removeByName( sManifest );
370 catch( Exception& )
372 if ( !m_bForceRecovery )
373 throw;
377 if ( !bManifestParsed && !m_bForceRecovery )
378 throw ZipIOException(
379 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Could not parse manifest.xml\n" ) ),
380 uno::Reference< uno::XInterface >() );
382 const OUString sMimetype ( RTL_CONSTASCII_USTRINGPARAM ( "mimetype" ) );
383 if ( m_xRootFolder->hasByName( sMimetype ) )
385 // get mediatype from the "mimetype" stream
386 ::rtl::OUString aPackageMediatype;
387 uno::Reference< lang::XUnoTunnel > xMimeTypeTunnel;
388 m_xRootFolder->getByName( sMimetype ) >>= xMimeTypeTunnel;
389 uno::Reference < io::XActiveDataSink > xMimeSink( xMimeTypeTunnel, UNO_QUERY );
390 if ( xMimeSink.is() )
392 uno::Reference< io::XInputStream > xMimeInStream = xMimeSink->getInputStream();
393 if ( xMimeInStream.is() )
395 // Mediatypes longer than 1024 symbols should not appear here
396 uno::Sequence< sal_Int8 > aData( 1024 );
397 sal_Int32 nRead = xMimeInStream->readBytes( aData, 1024 );
398 if ( nRead > aData.getLength() )
399 nRead = aData.getLength();
401 if ( nRead )
402 aPackageMediatype = ::rtl::OUString( (sal_Char*)aData.getConstArray(), nRead, RTL_TEXTENCODING_ASCII_US );
407 if ( !bManifestParsed )
409 // the manifest.xml could not be successfuly parsed, this is an inconsistent package
410 if ( aPackageMediatype.compareToAscii( RTL_CONSTASCII_STRINGPARAM( "application/vnd." ) ) == 0 )
412 // accept only types that look similar to own mediatypes
413 m_pRootFolder->SetMediaType( aPackageMediatype );
414 m_bMediaTypeFallbackUsed = sal_True;
417 else if ( !m_bForceRecovery )
419 // the mimetype stream should contain the information from manifest.xml
420 if ( !m_pRootFolder->GetMediaType().equals( aPackageMediatype ) )
421 throw ZipIOException(
422 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "mimetype conflicts with manifest.xml\n" ) ),
423 uno::Reference< uno::XInterface >() );
426 m_xRootFolder->removeByName( sMimetype );
429 sal_Bool bODF12AndOlder = ( m_pRootFolder->GetVersion().compareTo( ODFVER_012_TEXT ) >= 0 );
430 if ( !m_bForceRecovery && bODF12AndOlder && m_pRootFolder->LookForUnexpectedODF12Streams( ::rtl::OUString() ) )
432 // this is an ODF1.2 document that contains streams not referred in the manifest.xml
433 throw ZipIOException(
434 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "there are streams not referred in manifest.xml\n" ) ),
435 uno::Reference< uno::XInterface >() );
438 if ( bODF12AndOlder )
440 // it is ODF1.2 or later, let the META-INF folder be unavailable for user
441 m_xRootFolder->removeByName( sMeta );
446 void ZipPackage::parseContentType()
448 if ( m_nFormat == OFOPXML_FORMAT )
450 const ::rtl::OUString aContentTypes( RTL_CONSTASCII_USTRINGPARAM ( "[Content_Types].xml" ) );
451 try {
452 // the content type must exist in OFOPXML format!
453 if ( !m_xRootFolder->hasByName( aContentTypes ) )
454 throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Wrong format!" ) ),
455 uno::Reference< uno::XInterface >() );
457 uno::Reference< lang::XUnoTunnel > xTunnel;
458 uno::Any aAny = m_xRootFolder->getByName( aContentTypes );
459 aAny >>= xTunnel;
460 uno::Reference < io::XActiveDataSink > xSink( xTunnel, UNO_QUERY );
461 if ( xSink.is() )
463 uno::Reference< io::XInputStream > xInStream = xSink->getInputStream();
464 if ( xInStream.is() )
466 sal_Int32 nInd = 0;
467 // here aContentTypeInfo[0] - Defaults, and aContentTypeInfo[1] - Overrides
468 uno::Sequence< uno::Sequence< beans::StringPair > > aContentTypeInfo =
469 ::comphelper::OFOPXMLHelper::ReadContentTypeSequence( xInStream, m_xFactory );
471 if ( aContentTypeInfo.getLength() != 2 )
472 throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
474 // set the implicit types fist
475 for ( nInd = 0; nInd < aContentTypeInfo[0].getLength(); nInd++ )
476 m_pRootFolder->setChildStreamsTypeByExtension( aContentTypeInfo[0][nInd] );
478 // now set the explicit types
479 for ( nInd = 0; nInd < aContentTypeInfo[1].getLength(); nInd++ )
481 ::rtl::OUString aPath;
482 if ( aContentTypeInfo[1][nInd].First.toChar() == (sal_Unicode)'/' )
483 aPath = aContentTypeInfo[1][nInd].First.copy( 1 );
484 else
485 aPath = aContentTypeInfo[1][nInd].First;
487 if ( aPath.getLength() && hasByHierarchicalName( aPath ) )
489 uno::Any aIterAny = getByHierarchicalName( aPath );
490 uno::Reference < lang::XUnoTunnel > xIterTunnel;
491 aIterAny >>= xIterTunnel;
492 sal_Int64 nTest = xIterTunnel->getSomething( ZipPackageStream::static_getImplementationId() );
493 if ( nTest != 0 )
495 // this is a package stream, in OFOPXML format only streams can have mediatype
496 ZipPackageStream *pStream = reinterpret_cast < ZipPackageStream* > ( nTest );
497 pStream->SetMediaType( aContentTypeInfo[1][nInd].Second );
504 m_xRootFolder->removeByName( aContentTypes );
506 catch( uno::Exception& )
508 if ( !m_bForceRecovery )
509 throw;
514 void ZipPackage::getZipFileContents()
516 auto_ptr < ZipEnumeration > pEnum ( m_pZipFile->entries() );
517 ZipPackageStream *pPkgStream;
518 ZipPackageFolder *pPkgFolder, *pCurrent;
519 OUString sTemp, sDirName;
520 sal_Int32 nOldIndex, nIndex, nStreamIndex;
521 FolderHash::iterator aIter;
523 while (pEnum->hasMoreElements())
525 nIndex = nOldIndex = 0;
526 pCurrent = m_pRootFolder;
527 const ZipEntry & rEntry = *pEnum->nextElement();
528 const OUString & rName = rEntry.sPath;
530 nStreamIndex = rName.lastIndexOf ( '/' );
531 if ( nStreamIndex != -1 )
533 sDirName = rName.copy ( 0, nStreamIndex);
534 aIter = m_aRecent.find ( sDirName );
535 if ( aIter != m_aRecent.end() )
536 pCurrent = (*aIter).second;
539 if ( pCurrent == m_pRootFolder )
541 while ( (nIndex = rName.indexOf('/', nOldIndex) ) != -1 )
543 sTemp = rName.copy ( nOldIndex, nIndex - nOldIndex );
544 if (nIndex == nOldIndex)
545 break;
546 if ( !pCurrent->hasByName( sTemp ) )
548 pPkgFolder = new ZipPackageFolder( m_xFactory, m_nFormat, m_bAllowRemoveOnInsert );
549 pPkgFolder->setName( sTemp );
550 pPkgFolder->doSetParent( pCurrent, sal_True );
551 pCurrent = pPkgFolder;
553 else
554 pCurrent = pCurrent->doGetByName(sTemp).pFolder;
555 nOldIndex = nIndex+1;
557 if ( nStreamIndex != -1 && sDirName.getLength() )
558 m_aRecent [ sDirName ] = pCurrent;
560 if ( rName.getLength() -1 != nStreamIndex )
562 nStreamIndex++;
563 sTemp = rName.copy( nStreamIndex, rName.getLength() - nStreamIndex);
564 pPkgStream = new ZipPackageStream( *this, m_xFactory, m_bAllowRemoveOnInsert );
565 pPkgStream->SetPackageMember( sal_True );
566 pPkgStream->setZipEntryOnLoading( rEntry );
567 pPkgStream->setName( sTemp );
568 pPkgStream->doSetParent( pCurrent, sal_True );
572 if ( m_nFormat == PACKAGE_FORMAT )
573 parseManifest();
574 else if ( m_nFormat == OFOPXML_FORMAT )
575 parseContentType();
578 // XInitialization
579 void SAL_CALL ZipPackage::initialize( const Sequence< Any >& aArguments )
580 throw(Exception, RuntimeException)
582 RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "{ ZipPackage::initialize" );
583 sal_Bool bBadZipFile = sal_False, bHaveZipFile = sal_True;
584 uno::Reference< XProgressHandler > xProgressHandler;
585 beans::NamedValue aNamedValue;
587 if ( aArguments.getLength() )
589 for( int ind = 0; ind < aArguments.getLength(); ind++ )
591 OUString aParamUrl;
592 if ( (aArguments[ind] >>= aParamUrl))
594 m_eMode = e_IMode_URL;
597 sal_Int32 nParam = aParamUrl.indexOf( '?' );
598 if ( nParam >= 0 )
600 m_aURL = aParamUrl.copy( 0, nParam );
601 OUString aParam = aParamUrl.copy( nParam + 1 );
603 sal_Int32 nIndex = 0;
606 ::rtl::OUString aCommand = aParam.getToken( 0, '&', nIndex );
607 if ( aCommand.equals( OUString::createFromAscii( "repairpackage" ) ) )
609 m_bForceRecovery = sal_True;
610 break;
612 else if ( aCommand.equals( OUString::createFromAscii( "purezip" ) ) )
614 m_nFormat = ZIP_FORMAT;
615 m_pRootFolder->setPackageFormat_Impl( m_nFormat );
616 break;
618 else if ( aCommand.equals( OUString::createFromAscii( "ofopxml" ) ) )
620 m_nFormat = OFOPXML_FORMAT;
621 m_pRootFolder->setPackageFormat_Impl( m_nFormat );
622 break;
625 while ( nIndex >= 0 );
627 else
628 m_aURL = aParamUrl;
630 Content aContent ( m_aURL, uno::Reference < XCommandEnvironment >() );
631 Any aAny = aContent.getPropertyValue( OUString::createFromAscii( "Size" ) );
632 sal_uInt64 aSize = 0;
633 // kind of optimisation: treat empty files as nonexistent files
634 // and write to such files directly. Note that "Size" property is optional.
635 bool bHasSizeProperty = aAny >>= aSize;
636 if( !bHasSizeProperty || ( bHasSizeProperty && aSize ) )
638 uno::Reference < XActiveDataSink > xSink = new ZipPackageSink;
639 if (aContent.openStream ( xSink ) )
640 m_xContentStream = xSink->getInputStream();
642 else
643 bHaveZipFile = sal_False;
645 catch (com::sun::star::uno::Exception&)
647 // Exception derived from uno::Exception thrown. This probably
648 // means the file doesn't exist...we'll create it at
649 // commitChanges time
650 bHaveZipFile = sal_False;
653 else if ( (aArguments[ind] >>= m_xStream ) )
655 // a writable stream can implement both XStream & XInputStream
656 m_eMode = e_IMode_XStream;
657 m_xContentStream = m_xStream->getInputStream();
659 else if ( (aArguments[ind] >>= m_xContentStream) )
661 m_eMode = e_IMode_XInputStream;
663 else if ( ( aArguments[ind] >>= aNamedValue ) )
665 if ( aNamedValue.Name.equalsAscii( "RepairPackage" ) )
666 aNamedValue.Value >>= m_bForceRecovery;
667 else if ( aNamedValue.Name.equalsAscii( "PackageFormat" ) )
669 // setting this argument to true means Package format
670 // setting it to false means plain Zip format
672 sal_Bool bPackFormat = sal_True;
673 aNamedValue.Value >>= bPackFormat;
674 if ( !bPackFormat )
675 m_nFormat = ZIP_FORMAT;
677 m_pRootFolder->setPackageFormat_Impl( m_nFormat );
679 else if ( aNamedValue.Name.equalsAscii( "StorageFormat" ) )
681 ::rtl::OUString aFormatName;
682 aNamedValue.Value >>= aFormatName;
683 if ( aFormatName.equals( PACKAGE_STORAGE_FORMAT_STRING ) )
684 m_nFormat = PACKAGE_FORMAT;
685 else if ( aFormatName.equals( ZIP_STORAGE_FORMAT_STRING ) )
686 m_nFormat = ZIP_FORMAT;
687 else if ( aFormatName.equals( OFOPXML_STORAGE_FORMAT_STRING ) )
688 m_nFormat = OFOPXML_FORMAT;
689 else
690 throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 );
692 m_pRootFolder->setPackageFormat_Impl( m_nFormat );
694 else if ( aNamedValue.Name.equalsAscii( "AllowRemoveOnInsert" ) )
696 aNamedValue.Value >>= m_bAllowRemoveOnInsert;
697 m_pRootFolder->setRemoveOnInsertMode_Impl( m_bAllowRemoveOnInsert );
700 // for now the progress handler is not used, probably it will never be
701 // if ( aNamedValue.Name.equalsAscii( "ProgressHandler" )
703 else
705 // The URL is not acceptable
706 throw com::sun::star::uno::Exception ( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Bad arguments." ) ),
707 static_cast < ::cppu::OWeakObject * > ( this ) );
713 if (m_xContentStream.is())
715 // the stream must be seekable, if it is not it will be wrapped
716 m_xContentStream = ::comphelper::OSeekableInputWrapper::CheckSeekableCanWrap( m_xContentStream, m_xFactory );
717 m_xContentSeek = uno::Reference < XSeekable > ( m_xContentStream, UNO_QUERY );
718 if ( ! m_xContentSeek.is() )
719 throw com::sun::star::uno::Exception ( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "The package component _requires_ an XSeekable interface!" ) ),
720 static_cast < ::cppu::OWeakObject * > ( this ) );
722 if ( !m_xContentSeek->getLength() )
723 bHaveZipFile = sal_False;
725 else
726 bHaveZipFile = sal_False;
728 catch (com::sun::star::uno::Exception&)
730 // Exception derived from uno::Exception thrown. This probably
731 // means the file doesn't exist...we'll create it at
732 // commitChanges time
733 bHaveZipFile = sal_False;
735 if ( bHaveZipFile )
739 m_pZipFile = new ZipFile ( m_xContentStream, m_xFactory, sal_True, m_bForceRecovery, xProgressHandler );
740 getZipFileContents();
742 catch ( IOException & )
744 bBadZipFile = sal_True;
746 catch ( ZipException & )
748 bBadZipFile = sal_True;
750 catch ( Exception & )
752 if( m_pZipFile ) { delete m_pZipFile; m_pZipFile = NULL; }
753 throw;
756 if ( bBadZipFile )
758 // clean up the memory, and tell the UCB about the error
759 if( m_pZipFile ) { delete m_pZipFile; m_pZipFile = NULL; }
761 throw com::sun::star::packages::zip::ZipIOException (
762 OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Bad Zip File." ) ),
763 static_cast < ::cppu::OWeakObject * > ( this ) );
768 RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "} ZipPackage::initialize" );
771 Any SAL_CALL ZipPackage::getByHierarchicalName( const OUString& aName )
772 throw(NoSuchElementException, RuntimeException)
774 OUString sTemp, sDirName;
775 sal_Int32 nOldIndex, nIndex, nStreamIndex;
776 FolderHash::iterator aIter;
778 if ( (nIndex = aName.getLength() ) == 1 && *aName.getStr() == '/' )
779 return makeAny ( uno::Reference < XUnoTunnel > (m_pRootFolder) );
780 else
782 nStreamIndex = aName.lastIndexOf ( '/' );
783 bool bFolder = nStreamIndex == nIndex-1;
784 if ( nStreamIndex != -1 )
786 sDirName = aName.copy ( 0, nStreamIndex);
787 aIter = m_aRecent.find ( sDirName );
788 if ( aIter != m_aRecent.end() )
790 if ( bFolder )
792 sal_Int32 nDirIndex = aName.lastIndexOf ( '/', nStreamIndex );
793 sTemp = aName.copy ( nDirIndex == -1 ? 0 : nDirIndex+1, nStreamIndex-nDirIndex-1 );
794 if ( sTemp == (*aIter).second->getName() )
795 return makeAny ( uno::Reference < XUnoTunnel > ( (*aIter).second ) );
796 else
797 m_aRecent.erase ( aIter );
799 else
801 sTemp = aName.copy ( nStreamIndex + 1 );
802 if ( (*aIter).second->hasByName( sTemp ) )
803 return (*aIter).second->getByName( sTemp );
804 else
805 m_aRecent.erase( aIter );
809 else
811 if ( m_pRootFolder->hasByName ( aName ) )
812 return m_pRootFolder->getByName ( aName );
814 nOldIndex = 0;
815 ZipPackageFolder * pCurrent = m_pRootFolder;
816 ZipPackageFolder * pPrevious = NULL;
817 while ( ( nIndex = aName.indexOf('/', nOldIndex)) != -1)
819 sTemp = aName.copy (nOldIndex, nIndex - nOldIndex);
820 if ( nIndex == nOldIndex )
821 break;
822 if ( pCurrent->hasByName( sTemp ) )
824 pPrevious = pCurrent;
825 pCurrent = pCurrent->doGetByName(sTemp).pFolder;
827 else
828 throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
829 nOldIndex = nIndex+1;
831 if ( bFolder )
833 if (nStreamIndex != -1 )
834 m_aRecent[sDirName] = pPrevious;
835 return makeAny ( uno::Reference < XUnoTunnel > ( pCurrent ) );
837 else
839 sTemp = aName.copy( nOldIndex, aName.getLength() - nOldIndex);
840 if ( pCurrent->hasByName ( sTemp ) )
842 if (nStreamIndex != -1 )
843 m_aRecent[sDirName] = pCurrent;
844 return pCurrent->getByName( sTemp );
846 else
847 throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
852 sal_Bool SAL_CALL ZipPackage::hasByHierarchicalName( const OUString& aName )
853 throw(RuntimeException)
855 OUString sTemp, sDirName;
856 sal_Int32 nOldIndex, nIndex, nStreamIndex;
857 FolderHash::iterator aIter;
859 if ( (nIndex = aName.getLength() ) == 1 && *aName.getStr() == '/' )
860 return sal_True;
861 else
863 nStreamIndex = aName.lastIndexOf ( '/' );
864 bool bFolder = nStreamIndex == nIndex-1;
865 if ( nStreamIndex != -1 )
867 sDirName = aName.copy ( 0, nStreamIndex);
868 aIter = m_aRecent.find ( sDirName );
869 if ( aIter != m_aRecent.end() )
871 if ( bFolder )
873 sal_Int32 nDirIndex = aName.lastIndexOf ( '/', nStreamIndex );
874 sTemp = aName.copy ( nDirIndex == -1 ? 0 : nDirIndex+1, nStreamIndex-nDirIndex-1 );
875 if ( sTemp == (*aIter).second->getName() )
876 return sal_True;
877 else
878 m_aRecent.erase ( aIter );
880 else
882 sTemp = aName.copy ( nStreamIndex + 1 );
883 if ( (*aIter).second->hasByName( sTemp ) )
884 return sal_True;
885 else
886 m_aRecent.erase( aIter );
890 else
892 if ( m_pRootFolder->hasByName ( aName ) )
893 return sal_True;
895 ZipPackageFolder * pCurrent = m_pRootFolder;
896 ZipPackageFolder * pPrevious = NULL;
897 nOldIndex = 0;
898 while ( ( nIndex = aName.indexOf('/', nOldIndex)) != -1)
900 sTemp = aName.copy (nOldIndex, nIndex - nOldIndex);
901 if ( nIndex == nOldIndex )
902 break;
903 if ( pCurrent->hasByName( sTemp ) )
905 pPrevious = pCurrent;
906 pCurrent = pCurrent->doGetByName( sTemp ).pFolder;
908 else
909 return sal_False;
910 nOldIndex = nIndex+1;
912 if ( bFolder )
914 m_aRecent[sDirName] = pPrevious;
915 return sal_True;
917 else
919 sTemp = aName.copy( nOldIndex, aName.getLength() - nOldIndex);
921 if ( pCurrent->hasByName( sTemp ) )
923 m_aRecent[sDirName] = pCurrent;
924 return sal_True;
927 return sal_False;
931 // XSingleServiceFactory
932 uno::Reference< XInterface > SAL_CALL ZipPackage::createInstance( )
933 throw(Exception, RuntimeException)
935 uno::Reference < XInterface > xRef = *(new ZipPackageStream ( *this, m_xFactory, m_bAllowRemoveOnInsert ));
936 return xRef;
938 uno::Reference< XInterface > SAL_CALL ZipPackage::createInstanceWithArguments( const Sequence< Any >& aArguments )
939 throw(Exception, RuntimeException)
941 sal_Bool bArg = sal_False;
942 uno::Reference < XInterface > xRef;
943 if ( aArguments.getLength() )
944 aArguments[0] >>= bArg;
945 if (bArg)
946 xRef = *new ZipPackageFolder ( m_xFactory, m_nFormat, m_bAllowRemoveOnInsert );
947 else
948 xRef = *new ZipPackageStream ( *this, m_xFactory, m_bAllowRemoveOnInsert );
950 return xRef;
953 void ZipPackage::WriteMimetypeMagicFile( ZipOutputStream& aZipOut )
955 const OUString sMime ( RTL_CONSTASCII_USTRINGPARAM ( "mimetype" ) );
956 if (m_xRootFolder->hasByName( sMime ) )
957 m_xRootFolder->removeByName( sMime );
959 ZipEntry * pEntry = new ZipEntry;
960 sal_Int32 nBufferLength = m_pRootFolder->GetMediaType( ).getLength();
961 OString sMediaType = OUStringToOString( m_pRootFolder->GetMediaType(), RTL_TEXTENCODING_ASCII_US );
962 Sequence< sal_Int8 > aType( (sal_Int8*)sMediaType.getStr(),
963 nBufferLength );
966 pEntry->sPath = sMime;
967 pEntry->nMethod = STORED;
968 pEntry->nSize = pEntry->nCompressedSize = nBufferLength;
969 pEntry->nTime = ZipOutputStream::getCurrentDosTime();
971 CRC32 aCRC32;
972 aCRC32.update( aType );
973 pEntry->nCrc = aCRC32.getValue();
977 vos::ORef < EncryptionData > xEmpty;
978 aZipOut.putNextEntry( *pEntry, xEmpty );
979 aZipOut.write( aType, 0, nBufferLength );
980 aZipOut.closeEntry();
982 catch ( ::com::sun::star::io::IOException & r )
984 VOS_ENSURE( 0, "Error adding mimetype to the ZipOutputStream" );
985 throw WrappedTargetException(
986 OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Error adding mimetype to the ZipOutputStream!" ) ),
987 static_cast < OWeakObject * > ( this ),
988 makeAny( r ) );
992 void ZipPackage::WriteManifest( ZipOutputStream& aZipOut, const vector< Sequence < PropertyValue > >& aManList )
994 // Write the manifest
995 uno::Reference < XOutputStream > xManOutStream;
996 OUString sManifestWriter( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.manifest.ManifestWriter" ) );
997 uno::Reference < XManifestWriter > xWriter ( m_xFactory->createInstance( sManifestWriter ), UNO_QUERY );
998 if ( xWriter.is() )
1000 ZipEntry * pEntry = new ZipEntry;
1001 ZipPackageBuffer *pBuffer = new ZipPackageBuffer( n_ConstBufferSize );
1002 xManOutStream = uno::Reference < XOutputStream > (*pBuffer, UNO_QUERY);
1004 pEntry->sPath = OUString( RTL_CONSTASCII_USTRINGPARAM ( "META-INF/manifest.xml") );
1005 pEntry->nMethod = DEFLATED;
1006 pEntry->nCrc = pEntry->nSize = pEntry->nCompressedSize = -1;
1007 pEntry->nTime = ZipOutputStream::getCurrentDosTime();
1009 // Convert vector into a Sequence
1010 Sequence < Sequence < PropertyValue > > aManifestSequence ( aManList.size() );
1011 Sequence < PropertyValue > * pSequence = aManifestSequence.getArray();
1012 for (vector < Sequence < PropertyValue > >::const_iterator aIter = aManList.begin(), aEnd = aManList.end();
1013 aIter != aEnd;
1014 aIter++, pSequence++)
1015 *pSequence= (*aIter);
1016 xWriter->writeManifestSequence ( xManOutStream, aManifestSequence );
1018 sal_Int32 nBufferLength = static_cast < sal_Int32 > ( pBuffer->getPosition() );
1019 pBuffer->realloc( nBufferLength );
1021 // the manifest.xml is never encrypted - so pass an empty reference
1022 vos::ORef < EncryptionData > xEmpty;
1023 aZipOut.putNextEntry( *pEntry, xEmpty );
1024 aZipOut.write( pBuffer->getSequence(), 0, nBufferLength );
1025 aZipOut.closeEntry();
1027 else
1029 VOS_ENSURE ( 0, "Couldn't get a ManifestWriter!" );
1030 IOException aException;
1031 throw WrappedTargetException(
1032 OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Couldn't get a ManifestWriter!" ) ),
1033 static_cast < OWeakObject * > ( this ),
1034 makeAny( aException ) );
1038 void ZipPackage::WriteContentTypes( ZipOutputStream& aZipOut, const vector< Sequence < PropertyValue > >& aManList )
1040 const OUString sFullPath ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) );
1041 const OUString sMediaType ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) );
1043 ZipEntry* pEntry = new ZipEntry;
1044 ZipPackageBuffer *pBuffer = new ZipPackageBuffer( n_ConstBufferSize );
1045 uno::Reference< io::XOutputStream > xConTypeOutStream( *pBuffer, UNO_QUERY );
1047 pEntry->sPath = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "[Content_Types].xml") );
1048 pEntry->nMethod = DEFLATED;
1049 pEntry->nCrc = pEntry->nSize = pEntry->nCompressedSize = -1;
1050 pEntry->nTime = ZipOutputStream::getCurrentDosTime();
1052 // Convert vector into a Sequence
1053 // TODO/LATER: use Defaulst entries in future
1054 uno::Sequence< beans::StringPair > aDefaultsSequence;
1055 uno::Sequence< beans::StringPair > aOverridesSequence( aManList.size() );
1056 sal_Int32 nSeqLength = 0;
1057 for ( vector< uno::Sequence< beans::PropertyValue > >::const_iterator aIter = aManList.begin(),
1058 aEnd = aManList.end();
1059 aIter != aEnd;
1060 aIter++)
1062 ::rtl::OUString aPath;
1063 ::rtl::OUString aType;
1064 OSL_ENSURE( (*aIter)[PKG_MNFST_MEDIATYPE].Name.equals( sMediaType ) && (*aIter)[PKG_MNFST_FULLPATH].Name.equals( sFullPath ),
1065 "The mediatype sequence format is wrong!\n" );
1066 (*aIter)[PKG_MNFST_MEDIATYPE].Value >>= aType;
1067 if ( aType.getLength() )
1069 // only nonempty type makes sence here
1070 nSeqLength++;
1071 (*aIter)[PKG_MNFST_FULLPATH].Value >>= aPath;
1072 aOverridesSequence[nSeqLength-1].First = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/" ) ) + aPath;
1073 aOverridesSequence[nSeqLength-1].Second = aType;
1076 aOverridesSequence.realloc( nSeqLength );
1078 ::comphelper::OFOPXMLHelper::WriteContentSequence(
1079 xConTypeOutStream, aDefaultsSequence, aOverridesSequence, m_xFactory );
1081 sal_Int32 nBufferLength = static_cast < sal_Int32 > ( pBuffer->getPosition() );
1082 pBuffer->realloc( nBufferLength );
1084 // there is no encryption in this format currently
1085 vos::ORef < EncryptionData > xEmpty;
1086 aZipOut.putNextEntry( *pEntry, xEmpty );
1087 aZipOut.write( pBuffer->getSequence(), 0, nBufferLength );
1088 aZipOut.closeEntry();
1091 void ZipPackage::ConnectTo( const uno::Reference< io::XInputStream >& xInStream )
1093 m_xContentSeek.set( xInStream, uno::UNO_QUERY_THROW );
1094 m_xContentStream = xInStream;
1096 // seek back to the beginning of the temp file so we can read segments from it
1097 m_xContentSeek->seek( 0 );
1098 if ( m_pZipFile )
1099 m_pZipFile->setInputStream( m_xContentStream );
1100 else
1101 m_pZipFile = new ZipFile ( m_xContentStream, m_xFactory, sal_False );
1104 uno::Reference< io::XInputStream > ZipPackage::writeTempFile()
1106 // In case the target local file does not exist or empty
1107 // write directly to it otherwize create a temporary file to write to.
1108 // If a temporary file is created it is returned back by the method.
1109 // If the data written directly, xComponentStream will be switched here
1111 sal_Bool bUseTemp = sal_True;
1112 uno::Reference < io::XInputStream > xResult;
1113 uno::Reference < io::XInputStream > xTempIn;
1115 uno::Reference < io::XOutputStream > xTempOut;
1116 uno::Reference< io::XActiveDataStreamer > xSink;
1118 if ( m_eMode == e_IMode_URL && !m_pZipFile && isLocalFile_Impl( m_aURL ) )
1120 xSink = openOriginalForOutput();
1121 if( xSink.is() )
1123 uno::Reference< io::XStream > xStr = xSink->getStream();
1124 if( xStr.is() )
1126 xTempOut = xStr->getOutputStream();
1127 if( xTempOut.is() )
1128 bUseTemp = sal_False;
1132 else if ( m_eMode == e_IMode_XStream && !m_pZipFile )
1134 // write directly to an empty stream
1135 xTempOut = m_xStream->getOutputStream();
1136 if( xTempOut.is() )
1137 bUseTemp = sal_False;
1140 if( bUseTemp )
1142 // create temporary file
1143 const OUString sServiceName ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.TempFile" ) );
1144 uno::Reference < io::XStream > xTempFile( m_xFactory->createInstance ( sServiceName ), UNO_QUERY_THROW );
1145 xTempOut.set( xTempFile->getOutputStream(), UNO_SET_THROW );
1146 xTempIn.set( xTempFile->getInputStream(), UNO_SET_THROW );
1149 // Hand it to the ZipOutputStream:
1150 ZipOutputStream aZipOut ( xTempOut );
1151 aZipOut.setMethod(DEFLATED);
1152 aZipOut.setLevel(DEFAULT_COMPRESSION);
1156 if ( m_nFormat == PACKAGE_FORMAT )
1158 // Remove the old manifest.xml file as the
1159 // manifest will be re-generated and the
1160 // META-INF directory implicitly created if does not exist
1161 const OUString sMeta ( RTL_CONSTASCII_USTRINGPARAM ( "META-INF" ) );
1163 if ( m_xRootFolder->hasByName( sMeta ) )
1165 const OUString sManifest (RTL_CONSTASCII_USTRINGPARAM( "manifest.xml") );
1167 uno::Reference< XUnoTunnel > xTunnel;
1168 Any aAny = m_xRootFolder->getByName( sMeta );
1169 aAny >>= xTunnel;
1170 uno::Reference< XNameContainer > xMetaInfFolder( xTunnel, UNO_QUERY );
1171 if ( xMetaInfFolder.is() && xMetaInfFolder->hasByName( sManifest ) )
1172 xMetaInfFolder->removeByName( sManifest );
1175 // Write a magic file with mimetype
1176 WriteMimetypeMagicFile( aZipOut );
1178 else if ( m_nFormat == OFOPXML_FORMAT )
1180 // Remove the old [Content_Types].xml file as the
1181 // file will be re-generated
1183 const ::rtl::OUString aContentTypes( RTL_CONSTASCII_USTRINGPARAM ( "[Content_Types].xml" ) );
1185 if ( m_xRootFolder->hasByName( aContentTypes ) )
1186 m_xRootFolder->removeByName( aContentTypes );
1189 // Create a vector to store data for the manifest.xml file
1190 vector < Sequence < PropertyValue > > aManList;
1192 const OUString sMediaType ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) );
1193 const OUString sVersion ( RTL_CONSTASCII_USTRINGPARAM ( "Version" ) );
1194 const OUString sFullPath ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) );
1196 if ( m_nFormat == PACKAGE_FORMAT )
1198 Sequence < PropertyValue > aPropSeq ( PKG_SIZE_NOENCR_MNFST );
1199 aPropSeq [PKG_MNFST_MEDIATYPE].Name = sMediaType;
1200 aPropSeq [PKG_MNFST_MEDIATYPE].Value <<= m_pRootFolder->GetMediaType( );
1201 aPropSeq [PKG_MNFST_VERSION].Name = sVersion;
1202 aPropSeq [PKG_MNFST_VERSION].Value <<= m_pRootFolder->GetVersion( );
1203 aPropSeq [PKG_MNFST_FULLPATH].Name = sFullPath;
1204 aPropSeq [PKG_MNFST_FULLPATH].Value <<= OUString ( RTL_CONSTASCII_USTRINGPARAM ( "/" ) );
1206 aManList.push_back( aPropSeq );
1209 // Get a random number generator and seed it with current timestamp
1210 // This will be used to generate random salt and initialisation vectors
1211 // for encrypted streams
1212 TimeValue aTime;
1213 osl_getSystemTime( &aTime );
1214 rtlRandomPool aRandomPool = rtl_random_createPool ();
1215 rtl_random_addBytes ( aRandomPool, &aTime, 8 );
1218 // call saveContents (it will recursively save sub-directories
1219 OUString aEmptyString;
1220 m_pRootFolder->saveContents( aEmptyString, aManList, aZipOut, m_aEncryptionKey, aRandomPool );
1222 // Clean up random pool memory
1223 rtl_random_destroyPool ( aRandomPool );
1225 if( m_bUseManifest && m_nFormat == PACKAGE_FORMAT )
1227 WriteManifest( aZipOut, aManList );
1229 else if( m_nFormat == OFOPXML_FORMAT )
1231 WriteContentTypes( aZipOut, aManList );
1234 aZipOut.finish();
1236 if( bUseTemp )
1237 xResult = xTempIn;
1239 // Update our References to point to the new temp file
1240 if( !bUseTemp )
1242 // the case when the original contents were written directly
1243 xTempOut->flush();
1245 // in case the stream is based on a file it will implement the following interface
1246 // the call should be used to be sure that the contents are written to the file system
1247 uno::Reference< io::XAsyncOutputMonitor > asyncOutputMonitor( xTempOut, uno::UNO_QUERY );
1248 if ( asyncOutputMonitor.is() )
1249 asyncOutputMonitor->waitForCompletion();
1251 // no need to postpone switching to the new stream since the target was written directly
1252 uno::Reference< io::XInputStream > xNewStream;
1253 if ( m_eMode == e_IMode_URL )
1254 xNewStream = xSink->getStream()->getInputStream();
1255 else if ( m_eMode == e_IMode_XStream && m_xStream.is() )
1256 xNewStream = m_xStream->getInputStream();
1258 if ( xNewStream.is() )
1259 ConnectTo( xNewStream );
1262 catch ( uno::Exception& )
1264 if( bUseTemp )
1266 // no information loss appeares, thus no special handling is required
1267 uno::Any aCaught( ::cppu::getCaughtException() );
1269 // it is allowed to throw WrappedTargetException
1270 WrappedTargetException aException;
1271 if ( aCaught >>= aException )
1272 throw aException;
1274 throw WrappedTargetException(
1275 OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Problem writing the original content!" ) ),
1276 static_cast < OWeakObject * > ( this ),
1277 aCaught );
1279 else
1281 // the document is written directly, although it was empty it is important to notify that the writing has failed
1282 // TODO/LATER: let the package be able to recover in this situation
1283 ::rtl::OUString aErrTxt( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is unusable!" ) );
1284 embed::UseBackupException aException( aErrTxt, uno::Reference< uno::XInterface >(), ::rtl::OUString() );
1285 throw WrappedTargetException( aErrTxt,
1286 static_cast < OWeakObject * > ( this ),
1287 makeAny ( aException ) );
1291 return xResult;
1294 uno::Reference< XActiveDataStreamer > ZipPackage::openOriginalForOutput()
1296 // open and truncate the original file
1297 Content aOriginalContent (m_aURL, uno::Reference < XCommandEnvironment >() );
1298 uno::Reference< XActiveDataStreamer > xSink = new ActiveDataStreamer;
1300 if ( m_eMode == e_IMode_URL )
1304 sal_Bool bTruncSuccess = sal_False;
1308 Exception aDetect;
1309 sal_Int64 aSize = 0;
1310 Any aAny = aOriginalContent.setPropertyValue( OUString::createFromAscii( "Size" ), makeAny( aSize ) );
1311 if( !( aAny >>= aDetect ) )
1312 bTruncSuccess = sal_True;
1314 catch( Exception& )
1318 if( !bTruncSuccess )
1320 // the file is not accessible
1321 // just try to write an empty stream to it
1323 uno::Reference< XInputStream > xTempIn = new DummyInputStream; //uno::Reference< XInputStream >( xTempOut, UNO_QUERY );
1324 aOriginalContent.writeStream( xTempIn , sal_True );
1327 OpenCommandArgument2 aArg;
1328 aArg.Mode = OpenMode::DOCUMENT;
1329 aArg.Priority = 0; // unused
1330 aArg.Sink = xSink;
1331 aArg.Properties = Sequence< Property >( 0 ); // unused
1333 aOriginalContent.executeCommand( OUString::createFromAscii( "open" ), makeAny( aArg ) );
1335 catch( Exception& )
1337 // seems to be nonlocal file
1338 // temporary file mechanics should be used
1342 return xSink;
1345 // XChangesBatch
1346 void SAL_CALL ZipPackage::commitChanges()
1347 throw(WrappedTargetException, RuntimeException)
1349 // lock the component for the time of commiting
1350 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
1352 if ( m_eMode == e_IMode_XInputStream )
1354 IOException aException;
1355 throw WrappedTargetException( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is read only!" ) ),
1356 static_cast < OWeakObject * > ( this ), makeAny ( aException ) );
1359 RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "{ ZipPackage::commitChanges" );
1361 // first the writeTempFile is called, if it returns a stream the stream should be written to the target
1362 // if no stream was returned, the file was written directly, nothing should be done
1364 uno::Reference< io::XInputStream > xTempInStream = writeTempFile();
1365 if ( xTempInStream.is() )
1367 uno::Reference< io::XSeekable > xTempSeek( xTempInStream, uno::UNO_QUERY_THROW );
1369 // switch to the new temporary stream only after the transfer
1370 PostinitializationGuard aPostInitGuard( xTempInStream, *this );
1372 if ( m_eMode == e_IMode_XStream )
1374 // First truncate our output stream
1375 uno::Reference < XOutputStream > xOutputStream;
1377 // preparation for copy step
1380 xTempSeek->seek( 0 );
1382 xOutputStream = m_xStream->getOutputStream();
1383 uno::Reference < XTruncate > xTruncate ( xOutputStream, UNO_QUERY );
1384 if ( !xTruncate.is() )
1385 throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1387 // after successful truncation the original file contents are already lost
1388 xTruncate->truncate();
1390 catch( uno::Exception& r )
1392 throw WrappedTargetException( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is read only!" ) ),
1393 static_cast < OWeakObject * > ( this ), makeAny ( r ) );
1398 // then copy the contents of the tempfile to our output stream
1399 ::comphelper::OStorageHelper::CopyInputToOutput( xTempInStream, xOutputStream );
1400 xOutputStream->flush();
1401 uno::Reference< io::XAsyncOutputMonitor > asyncOutputMonitor(
1402 xOutputStream, uno::UNO_QUERY);
1403 if (asyncOutputMonitor.is()) {
1404 asyncOutputMonitor->waitForCompletion();
1407 catch( uno::Exception& )
1409 // if anything goes wrong in this block the target file becomes corrupted
1410 // so an exception should be thrown as a notification about it
1411 // and the package must disconnect from the stream
1412 DisconnectFromTargetAndThrowException_Impl( xTempInStream );
1415 else if ( m_eMode == e_IMode_URL )
1417 uno::Reference< XOutputStream > aOrigFileStream;
1418 sal_Bool bCanBeCorrupted = sal_False;
1420 if( isLocalFile_Impl( m_aURL ) )
1422 // write directly in case of local file
1423 uno::Reference< ::com::sun::star::ucb::XSimpleFileAccess > xSimpleAccess(
1424 m_xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ),
1425 uno::UNO_QUERY );
1426 OSL_ENSURE( xSimpleAccess.is(), "Can't instatiate SimpleFileAccess service!\n" );
1427 uno::Reference< io::XTruncate > xOrigTruncate;
1428 if ( xSimpleAccess.is() )
1432 aOrigFileStream = xSimpleAccess->openFileWrite( m_aURL );
1433 xOrigTruncate = uno::Reference< io::XTruncate >( aOrigFileStream, uno::UNO_QUERY_THROW );
1434 // after successful truncation the file is already corrupted
1435 xOrigTruncate->truncate();
1437 catch( uno::Exception& )
1441 if( xOrigTruncate.is() )
1445 ::comphelper::OStorageHelper::CopyInputToOutput( xTempInStream, aOrigFileStream );
1446 aOrigFileStream->closeOutput();
1448 catch( uno::Exception& )
1450 try {
1451 aOrigFileStream->closeOutput();
1452 } catch ( uno::Exception& ) {}
1454 aOrigFileStream = uno::Reference< XOutputStream >();
1455 // the original file can already be corrupted
1456 bCanBeCorrupted = sal_True;
1461 if( !aOrigFileStream.is() )
1465 uno::Reference < XPropertySet > xPropSet ( xTempInStream, UNO_QUERY );
1466 OSL_ENSURE( xPropSet.is(), "This is a temporary file that must implement XPropertySet!\n" );
1467 if ( !xPropSet.is() )
1468 throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1470 OUString sTargetFolder = m_aURL.copy ( 0, m_aURL.lastIndexOf ( static_cast < sal_Unicode > ( '/' ) ) );
1471 Content aContent ( sTargetFolder, uno::Reference < XCommandEnvironment > () );
1473 OUString sTempURL;
1474 Any aAny = xPropSet->getPropertyValue ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Uri" ) ) );
1475 aAny >>= sTempURL;
1477 TransferInfo aInfo;
1478 aInfo.NameClash = NameClash::OVERWRITE;
1479 aInfo.MoveData = sal_False;
1480 aInfo.SourceURL = sTempURL;
1481 aInfo.NewTitle = rtl::Uri::decode ( m_aURL.copy ( 1 + m_aURL.lastIndexOf ( static_cast < sal_Unicode > ( '/' ) ) ),
1482 rtl_UriDecodeWithCharset,
1483 RTL_TEXTENCODING_UTF8 );
1484 aAny <<= aInfo;
1486 // if the file is still not corrupted, it can become after the next step
1487 aContent.executeCommand ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "transfer" ) ), aAny );
1489 catch (::com::sun::star::uno::Exception& r)
1491 if ( bCanBeCorrupted )
1492 DisconnectFromTargetAndThrowException_Impl( xTempInStream );
1494 throw WrappedTargetException(
1495 OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package may be read only!" ) ),
1496 static_cast < OWeakObject * > ( this ),
1497 makeAny ( r ) );
1503 // after successful storing it can be set to false
1504 m_bMediaTypeFallbackUsed = sal_False;
1506 RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "} ZipPackage::commitChanges" );
1509 void ZipPackage::DisconnectFromTargetAndThrowException_Impl( const uno::Reference< io::XInputStream >& xTempStream )
1511 m_xStream = uno::Reference< io::XStream >( xTempStream, uno::UNO_QUERY );
1512 if ( m_xStream.is() )
1513 m_eMode = e_IMode_XStream;
1514 else
1515 m_eMode = e_IMode_XInputStream;
1517 ::rtl::OUString aTempURL;
1518 try {
1519 uno::Reference< beans::XPropertySet > xTempFile( xTempStream, uno::UNO_QUERY_THROW );
1520 uno::Any aUrl = xTempFile->getPropertyValue( ::rtl::OUString::createFromAscii( "Uri" ) );
1521 aUrl >>= aTempURL;
1522 xTempFile->setPropertyValue( ::rtl::OUString::createFromAscii( "RemoveFile" ),
1523 uno::makeAny( sal_False ) );
1525 catch ( uno::Exception& )
1527 OSL_ENSURE( sal_False, "These calls are pretty simple, they should not fail!\n" );
1530 ::rtl::OUString aErrTxt( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is read only!" ) );
1531 embed::UseBackupException aException( aErrTxt, uno::Reference< uno::XInterface >(), aTempURL );
1532 throw WrappedTargetException( aErrTxt,
1533 static_cast < OWeakObject * > ( this ),
1534 makeAny ( aException ) );
1537 sal_Bool SAL_CALL ZipPackage::hasPendingChanges( )
1538 throw(RuntimeException)
1540 return sal_False;
1542 Sequence< ElementChange > SAL_CALL ZipPackage::getPendingChanges( )
1543 throw(RuntimeException)
1545 return Sequence < ElementChange > ();
1549 * Function to create a new component instance; is needed by factory helper implementation.
1550 * @param xMgr service manager to if the components needs other component instances
1552 uno::Reference < XInterface >SAL_CALL ZipPackage_createInstance(
1553 const uno::Reference< XMultiServiceFactory > & xMgr )
1555 return uno::Reference< XInterface >( *new ZipPackage(xMgr) );
1558 OUString ZipPackage::static_getImplementationName()
1560 return OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.comp.ZipPackage" ) );
1563 Sequence< OUString > ZipPackage::static_getSupportedServiceNames()
1565 Sequence< OUString > aNames(1);
1566 aNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.Package" ) );
1567 return aNames;
1569 sal_Bool SAL_CALL ZipPackage::static_supportsService( OUString const & rServiceName )
1571 return rServiceName == getSupportedServiceNames()[0];
1574 OUString ZipPackage::getImplementationName()
1575 throw (RuntimeException)
1577 return static_getImplementationName();
1580 Sequence< OUString > ZipPackage::getSupportedServiceNames()
1581 throw (RuntimeException)
1583 return static_getSupportedServiceNames();
1585 sal_Bool SAL_CALL ZipPackage::supportsService( OUString const & rServiceName )
1586 throw (RuntimeException)
1588 return static_supportsService ( rServiceName );
1590 uno::Reference < XSingleServiceFactory > ZipPackage::createServiceFactory( uno::Reference < XMultiServiceFactory > const & rServiceFactory )
1592 return cppu::createSingleFactory (rServiceFactory,
1593 static_getImplementationName(),
1594 ZipPackage_createInstance,
1595 static_getSupportedServiceNames());
1598 // XUnoTunnel
1599 Sequence< sal_Int8 > ZipPackage::getUnoTunnelImplementationId( void )
1600 throw (RuntimeException)
1602 static ::cppu::OImplementationId * pId = 0;
1603 if (! pId)
1605 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
1606 if (! pId)
1608 static ::cppu::OImplementationId aId;
1609 pId = &aId;
1612 return pId->getImplementationId();
1615 sal_Int64 SAL_CALL ZipPackage::getSomething( const Sequence< sal_Int8 >& aIdentifier )
1616 throw(RuntimeException)
1618 if (aIdentifier.getLength() == 16 && 0 == rtl_compareMemory(getUnoTunnelImplementationId().getConstArray(), aIdentifier.getConstArray(), 16 ) )
1619 return reinterpret_cast < sal_Int64 > ( this );
1620 return 0;
1623 uno::Reference< XPropertySetInfo > SAL_CALL ZipPackage::getPropertySetInfo( )
1624 throw(RuntimeException)
1626 return uno::Reference < XPropertySetInfo > ();
1628 void SAL_CALL ZipPackage::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
1629 throw(UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
1631 if ( m_nFormat != PACKAGE_FORMAT )
1632 throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1634 if (aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("HasEncryptedEntries") )
1635 ||aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("HasNonEncryptedEntries") )
1636 ||aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("MediaTypeFallbackUsed") ) )
1637 throw PropertyVetoException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1638 else if (aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("EncryptionKey") ) )
1640 if (!( aValue >>= m_aEncryptionKey ) )
1641 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 2 );
1643 else if (aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("UseManifest") ) )
1645 if (!( aValue >>= m_bUseManifest ) )
1646 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 2 );
1648 else
1649 throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1651 Any SAL_CALL ZipPackage::getPropertyValue( const OUString& PropertyName )
1652 throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
1654 // TODO/LATER: Activate the check when zip-ucp is ready
1655 // if ( m_nFormat != PACKAGE_FORMAT )
1656 // throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1658 Any aAny;
1659 if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "EncryptionKey" ) ) )
1661 aAny <<= m_aEncryptionKey;
1662 return aAny;
1664 else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "HasEncryptedEntries" ) ) )
1666 aAny <<= m_bHasEncryptedEntries;
1667 return aAny;
1669 else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "HasNonEncryptedEntries" ) ) )
1671 aAny <<= m_bHasNonEncryptedEntries;
1672 return aAny;
1674 else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "UseManifest" ) ) )
1676 aAny <<= m_bUseManifest;
1677 return aAny;
1679 else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "MediaTypeFallbackUsed" ) ) )
1681 aAny <<= m_bMediaTypeFallbackUsed;
1682 return aAny;
1684 throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1686 void SAL_CALL ZipPackage::addPropertyChangeListener( const OUString& /*aPropertyName*/, const uno::Reference< XPropertyChangeListener >& /*xListener*/ )
1687 throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
1690 void SAL_CALL ZipPackage::removePropertyChangeListener( const OUString& /*aPropertyName*/, const uno::Reference< XPropertyChangeListener >& /*aListener*/ )
1691 throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
1694 void SAL_CALL ZipPackage::addVetoableChangeListener( const OUString& /*PropertyName*/, const uno::Reference< XVetoableChangeListener >& /*aListener*/ )
1695 throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
1698 void SAL_CALL ZipPackage::removeVetoableChangeListener( const OUString& /*PropertyName*/, const uno::Reference< XVetoableChangeListener >& /*aListener*/ )
1699 throw(UnknownPropertyException, WrappedTargetException, RuntimeException)