1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ZipPackage.cxx,v $
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>
75 #include <osl/file.hxx>
76 #include "com/sun/star/io/XAsyncOutputMonitor.hpp"
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>
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"
112 sal_Bool
isLocalFile_Impl( ::rtl::OUString aURL
)
114 ::rtl::OUString aSystemPath
;
115 ContentBroker
* pBroker
= ContentBroker::get();
118 ::rtl::OUString aRet
;
119 if ( FileBase::getSystemPathFromFileURL( aURL
, aRet
) == FileBase::E_None
)
124 uno::Reference
< XContentProviderManager
> xManager
=
125 pBroker
->getContentProviderManagerInterface();
128 aSystemPath
= getSystemPathFromFileURL( xManager
, aURL
);
135 return ( aSystemPath
.getLength() != 0 );
138 class PostinitializationGuard
140 uno::Reference
< io::XInputStream
> m_xTempStream
;
142 ZipPackage
& m_rZipPackage
;
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
;
166 virtual uno::Reference
< XStream
> SAL_CALL
getStream()
167 throw( RuntimeException
)
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
)
181 virtual sal_Int32 SAL_CALL
readSomeBytes( Sequence
< sal_Int8
>&, sal_Int32
)
182 throw ( NotConnectedException
, BufferSizeExceededException
, IOException
, RuntimeException
)
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
)
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
)
214 m_xRootFolder
= m_pRootFolder
= new ZipPackageFolder( m_xFactory
, m_nFormat
, m_bAllowRemoveOnInsert
);
217 ZipPackage::~ZipPackage( void )
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.
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();
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") );
250 uno::Reference
< XUnoTunnel
> xTunnel
;
251 Any aAny
= m_xRootFolder
->getByName( sMeta
);
253 uno::Reference
< XNameContainer
> xMetaInfFolder( xTunnel
, UNO_QUERY
);
254 if ( xMetaInfFolder
.is() && xMetaInfFolder
->hasByName( sManifest
) )
256 aAny
= xMetaInfFolder
->getByName( sManifest
);
258 uno::Reference
< XActiveDataSink
> xSink (xTunnel
, UNO_QUERY
);
261 OUString
sManifestReader ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.manifest.ManifestReader" ) );
262 uno::Reference
< XManifestReader
> xReader (m_xFactory
->createInstance( sManifestReader
), UNO_QUERY
);
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
;
311 if ((nTest
= xUnoTunnel
->getSomething(ZipPackageFolder::static_getImplementationId())) != 0)
313 pFolder
= reinterpret_cast < ZipPackageFolder
* > ( nTest
);
314 pFolder
->SetMediaType ( sMediaType
);
315 pFolder
->SetVersion ( sVersion
);
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
);
336 pStream
->setIterationCount ( nCount
);
339 pStream
->setSize ( nSize
);
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
;
355 m_bHasNonEncryptedEntries
= sal_True
;
360 bManifestParsed
= sal_True
;
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
);
372 if ( !m_bForceRecovery
)
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();
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" ) );
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
);
460 uno::Reference
< io::XActiveDataSink
> xSink( xTunnel
, UNO_QUERY
);
463 uno::Reference
< io::XInputStream
> xInStream
= xSink
->getInputStream();
464 if ( xInStream
.is() )
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 );
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() );
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
)
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
)
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
;
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
)
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
)
574 else if ( m_nFormat
== OFOPXML_FORMAT
)
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
++ )
592 if ( (aArguments
[ind
] >>= aParamUrl
))
594 m_eMode
= e_IMode_URL
;
597 sal_Int32 nParam
= aParamUrl
.indexOf( '?' );
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
;
612 else if ( aCommand
.equals( OUString::createFromAscii( "purezip" ) ) )
614 m_nFormat
= ZIP_FORMAT
;
615 m_pRootFolder
->setPackageFormat_Impl( m_nFormat
);
618 else if ( aCommand
.equals( OUString::createFromAscii( "ofopxml" ) ) )
620 m_nFormat
= OFOPXML_FORMAT
;
621 m_pRootFolder
->setPackageFormat_Impl( m_nFormat
);
625 while ( nIndex
>= 0 );
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();
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
;
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
;
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" )
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
;
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
;
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
; }
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
) );
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() )
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
) );
797 m_aRecent
.erase ( aIter
);
801 sTemp
= aName
.copy ( nStreamIndex
+ 1 );
802 if ( (*aIter
).second
->hasByName( sTemp
) )
803 return (*aIter
).second
->getByName( sTemp
);
805 m_aRecent
.erase( aIter
);
811 if ( m_pRootFolder
->hasByName ( aName
) )
812 return m_pRootFolder
->getByName ( aName
);
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
)
822 if ( pCurrent
->hasByName( sTemp
) )
824 pPrevious
= pCurrent
;
825 pCurrent
= pCurrent
->doGetByName(sTemp
).pFolder
;
828 throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX
) ), uno::Reference
< uno::XInterface
>() );
829 nOldIndex
= nIndex
+1;
833 if (nStreamIndex
!= -1 )
834 m_aRecent
[sDirName
] = pPrevious
;
835 return makeAny ( uno::Reference
< XUnoTunnel
> ( pCurrent
) );
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
);
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() == '/' )
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() )
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() )
878 m_aRecent
.erase ( aIter
);
882 sTemp
= aName
.copy ( nStreamIndex
+ 1 );
883 if ( (*aIter
).second
->hasByName( sTemp
) )
886 m_aRecent
.erase( aIter
);
892 if ( m_pRootFolder
->hasByName ( aName
) )
895 ZipPackageFolder
* pCurrent
= m_pRootFolder
;
896 ZipPackageFolder
* pPrevious
= NULL
;
898 while ( ( nIndex
= aName
.indexOf('/', nOldIndex
)) != -1)
900 sTemp
= aName
.copy (nOldIndex
, nIndex
- nOldIndex
);
901 if ( nIndex
== nOldIndex
)
903 if ( pCurrent
->hasByName( sTemp
) )
905 pPrevious
= pCurrent
;
906 pCurrent
= pCurrent
->doGetByName( sTemp
).pFolder
;
910 nOldIndex
= nIndex
+1;
914 m_aRecent
[sDirName
] = pPrevious
;
919 sTemp
= aName
.copy( nOldIndex
, aName
.getLength() - nOldIndex
);
921 if ( pCurrent
->hasByName( sTemp
) )
923 m_aRecent
[sDirName
] = pCurrent
;
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
));
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
;
946 xRef
= *new ZipPackageFolder ( m_xFactory
, m_nFormat
, m_bAllowRemoveOnInsert
);
948 xRef
= *new ZipPackageStream ( *this, m_xFactory
, m_bAllowRemoveOnInsert
);
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(),
966 pEntry
->sPath
= sMime
;
967 pEntry
->nMethod
= STORED
;
968 pEntry
->nSize
= pEntry
->nCompressedSize
= nBufferLength
;
969 pEntry
->nTime
= ZipOutputStream::getCurrentDosTime();
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 ),
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
);
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();
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();
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();
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
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 );
1099 m_pZipFile
->setInputStream( m_xContentStream
);
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();
1123 uno::Reference
< io::XStream
> xStr
= xSink
->getStream();
1126 xTempOut
= xStr
->getOutputStream();
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();
1137 bUseTemp
= sal_False
;
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
);
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
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
);
1239 // Update our References to point to the new temp file
1242 // the case when the original contents were written directly
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
& )
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
)
1274 throw WrappedTargetException(
1275 OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX
"Problem writing the original content!" ) ),
1276 static_cast < OWeakObject
* > ( this ),
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
) );
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
;
1309 sal_Int64 aSize
= 0;
1310 Any aAny
= aOriginalContent
.setPropertyValue( OUString::createFromAscii( "Size" ), makeAny( aSize
) );
1311 if( !( aAny
>>= aDetect
) )
1312 bTruncSuccess
= sal_True
;
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
1331 aArg
.Properties
= Sequence
< Property
>( 0 ); // unused
1333 aOriginalContent
.executeCommand( OUString::createFromAscii( "open" ), makeAny( aArg
) );
1337 // seems to be nonlocal file
1338 // temporary file mechanics should be used
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" ) ),
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
& )
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
> () );
1474 Any aAny
= xPropSet
->getPropertyValue ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Uri" ) ) );
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
);
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 ),
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
;
1515 m_eMode
= e_IMode_XInputStream
;
1517 ::rtl::OUString aTempURL
;
1519 uno::Reference
< beans::XPropertySet
> xTempFile( xTempStream
, uno::UNO_QUERY_THROW
);
1520 uno::Any aUrl
= xTempFile
->getPropertyValue( ::rtl::OUString::createFromAscii( "Uri" ) );
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
)
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" ) );
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());
1599 Sequence
< sal_Int8
> ZipPackage::getUnoTunnelImplementationId( void )
1600 throw (RuntimeException
)
1602 static ::cppu::OImplementationId
* pId
= 0;
1605 ::osl::MutexGuard
aGuard( ::osl::Mutex::getGlobalMutex() );
1608 static ::cppu::OImplementationId 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 );
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 );
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 >() );
1659 if (PropertyName
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "EncryptionKey" ) ) )
1661 aAny
<<= m_aEncryptionKey
;
1664 else if (PropertyName
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "HasEncryptedEntries" ) ) )
1666 aAny
<<= m_bHasEncryptedEntries
;
1669 else if (PropertyName
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "HasNonEncryptedEntries" ) ) )
1671 aAny
<<= m_bHasNonEncryptedEntries
;
1674 else if (PropertyName
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "UseManifest" ) ) )
1676 aAny
<<= m_bUseManifest
;
1679 else if (PropertyName
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "MediaTypeFallbackUsed" ) ) )
1681 aAny
<<= m_bMediaTypeFallbackUsed
;
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
)