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 , bHasEncryptedEntries ( sal_False
)
203 , bUseManifest ( sal_True
)
204 , bForceRecovery ( sal_False
)
205 , m_bMediaTypeFallbackUsed ( sal_False
)
206 , m_nFormat( PACKAGE_FORMAT
) // package is the default format
207 , m_bAllowRemoveOnInsert( sal_True
)
208 , eMode ( e_IMode_None
)
209 , xFactory( xNewFactory
)
210 , pRootFolder( NULL
)
213 xRootFolder
= pRootFolder
= new ZipPackageFolder( xFactory
, m_nFormat
, m_bAllowRemoveOnInsert
);
216 ZipPackage::~ZipPackage( void )
220 // All folders and streams contain pointers to their parents, when a parent diappeares
221 // it should disconnect all the children from itself during destruction automatically.
222 // So there is no need in explicit pRootFolder->releaseUpwardRef() call here any more
223 // since pRootFolder has no parent and cleaning of it's children will be done automatically
224 // during pRootFolder dieing by refcount.
227 // As all folders and streams contain references to their parents,
228 // we must remove these references so that they will be deleted when
229 // the hash_map of the root folder is cleared, releasing all subfolders
230 // and substreams which in turn release theirs, etc. When xRootFolder is
231 // released when this destructor completes, the folder tree should be
232 // deleted fully (and automagically).
234 pRootFolder
->releaseUpwardRef();
238 void ZipPackage::parseManifest()
240 if ( m_nFormat
== PACKAGE_FORMAT
)
242 sal_Bool bManifestParsed
= sal_False
;
243 const OUString
sMeta ( RTL_CONSTASCII_USTRINGPARAM ( "META-INF" ) );
244 if ( xRootFolder
->hasByName( sMeta
) )
246 const OUString
sManifest (RTL_CONSTASCII_USTRINGPARAM( "manifest.xml") );
249 uno::Reference
< XUnoTunnel
> xTunnel
;
250 Any aAny
= xRootFolder
->getByName( sMeta
);
252 uno::Reference
< XNameContainer
> xMetaInfFolder( xTunnel
, UNO_QUERY
);
253 if ( xMetaInfFolder
.is() && xMetaInfFolder
->hasByName( sManifest
) )
255 aAny
= xMetaInfFolder
->getByName( sManifest
);
257 uno::Reference
< XActiveDataSink
> xSink (xTunnel
, UNO_QUERY
);
260 OUString
sManifestReader ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.manifest.ManifestReader" ) );
261 uno::Reference
< XManifestReader
> xReader (xFactory
->createInstance( sManifestReader
), UNO_QUERY
);
264 const OUString
sPropFullPath ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) );
265 const OUString
sPropVersion ( RTL_CONSTASCII_USTRINGPARAM ( "Version" ) );
266 const OUString
sPropMediaType ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) );
267 const OUString
sPropInitialisationVector ( RTL_CONSTASCII_USTRINGPARAM ( "InitialisationVector" ) );
268 const OUString
sPropSalt ( RTL_CONSTASCII_USTRINGPARAM ( "Salt" ) );
269 const OUString
sPropIterationCount ( RTL_CONSTASCII_USTRINGPARAM ( "IterationCount" ) );
270 const OUString
sPropSize ( RTL_CONSTASCII_USTRINGPARAM ( "Size" ) );
271 const OUString
sPropDigest ( RTL_CONSTASCII_USTRINGPARAM ( "Digest" ) );
273 Sequence
< Sequence
< PropertyValue
> > aManifestSequence
= xReader
->readManifestSequence ( xSink
->getInputStream() );
274 sal_Int32 nLength
= aManifestSequence
.getLength();
275 const Sequence
< PropertyValue
> *pSequence
= aManifestSequence
.getConstArray();
276 ZipPackageStream
*pStream
= NULL
;
277 ZipPackageFolder
*pFolder
= NULL
;
279 for (sal_Int32 i
= 0; i
< nLength
; i
++, pSequence
++)
281 OUString sPath
, sMediaType
, sVersion
;
282 const PropertyValue
*pValue
= pSequence
->getConstArray();
283 const Any
*pSalt
= NULL
, *pVector
= NULL
, *pCount
= NULL
, *pSize
= NULL
, *pDigest
= NULL
;
284 for (sal_Int32 j
= 0, nNum
= pSequence
->getLength(); j
< nNum
; j
++ )
286 if (pValue
[j
].Name
.equals( sPropFullPath
) )
287 pValue
[j
].Value
>>= sPath
;
288 else if (pValue
[j
].Name
.equals( sPropVersion
) )
289 pValue
[j
].Value
>>= sVersion
;
290 else if (pValue
[j
].Name
.equals( sPropMediaType
) )
291 pValue
[j
].Value
>>= sMediaType
;
292 else if (pValue
[j
].Name
.equals( sPropSalt
) )
293 pSalt
= &(pValue
[j
].Value
);
294 else if (pValue
[j
].Name
.equals( sPropInitialisationVector
) )
295 pVector
= &(pValue
[j
].Value
);
296 else if (pValue
[j
].Name
.equals( sPropIterationCount
) )
297 pCount
= &(pValue
[j
].Value
);
298 else if (pValue
[j
].Name
.equals( sPropSize
) )
299 pSize
= &(pValue
[j
].Value
);
300 else if (pValue
[j
].Name
.equals( sPropDigest
) )
301 pDigest
= &(pValue
[j
].Value
);
303 if (sPath
.getLength() && hasByHierarchicalName ( sPath
) )
305 aAny
= getByHierarchicalName( sPath
);
306 uno::Reference
< XUnoTunnel
> xUnoTunnel
;
309 if ((nTest
= xUnoTunnel
->getSomething(ZipPackageFolder::static_getImplementationId())) != 0)
311 pFolder
= reinterpret_cast < ZipPackageFolder
* > ( nTest
);
312 pFolder
->SetMediaType ( sMediaType
);
313 pFolder
->SetVersion ( sVersion
);
317 pStream
= reinterpret_cast < ZipPackageStream
* > ( xUnoTunnel
->getSomething(ZipPackageStream::static_getImplementationId()));
318 pStream
->SetMediaType ( sMediaType
);
320 if (pSalt
&& pVector
&& pCount
&& pSize
)
322 Sequence
< sal_uInt8
> aSequence
;
323 sal_Int32 nCount
= 0, nSize
= 0;
324 pStream
->SetToBeEncrypted ( sal_True
);
326 *pSalt
>>= aSequence
;
327 pStream
->setSalt ( aSequence
);
329 *pVector
>>= aSequence
;
330 pStream
->setInitialisationVector ( aSequence
);
333 pStream
->setIterationCount ( nCount
);
336 pStream
->setSize ( nSize
);
340 *pDigest
>>= aSequence
;
341 pStream
->setDigest ( aSequence
);
344 pStream
->SetToBeCompressed ( sal_True
);
345 pStream
->SetToBeEncrypted ( sal_True
);
346 pStream
->SetIsEncrypted ( sal_True
);
347 if ( !bHasEncryptedEntries
&& pStream
->getName().compareToAscii ( "content.xml" ) == 0 )
348 bHasEncryptedEntries
= sal_True
;
354 bManifestParsed
= sal_True
;
357 VOS_ENSURE ( 0, "Couldn't get a ManifestReader!" ); // throw RuntimeException?
360 // now hide the manifest.xml file from user
361 xMetaInfFolder
->removeByName( sManifest
);
366 if ( !bForceRecovery
)
371 const OUString
sMimetype ( RTL_CONSTASCII_USTRINGPARAM ( "mimetype" ) );
372 if ( xRootFolder
->hasByName( sMimetype
) )
374 if ( !bManifestParsed
)
376 // try to get mediatype from the "mimetype" stream
377 uno::Reference
< lang::XUnoTunnel
> xMimeTypeTunnel
;
378 xRootFolder
->getByName( sMimetype
) >>= xMimeTypeTunnel
;
379 uno::Reference
< io::XActiveDataSink
> xMimeSink( xMimeTypeTunnel
, UNO_QUERY
);
380 if ( xMimeSink
.is() )
382 uno::Reference
< io::XInputStream
> xMimeInStream
= xMimeSink
->getInputStream();
383 if ( xMimeInStream
.is() )
385 // Mediatypes longer than 1024 symbols should not appear here
386 uno::Sequence
< sal_Int8
> aData( 1024 );
387 sal_Int32 nRead
= xMimeInStream
->readBytes( aData
, 1024 );
388 OSL_ENSURE( nRead
== aData
.getLength(), "Difference between reading result and data!\n" );
389 if ( nRead
> aData
.getLength() )
390 nRead
= aData
.getLength();
393 ::rtl::OUString
aFallBack( (sal_Char
*)aData
.getConstArray(), nRead
, RTL_TEXTENCODING_ASCII_US
);
394 if ( aFallBack
.compareToAscii( RTL_CONSTASCII_STRINGPARAM( "application/vnd." ) ) == 0 )
396 // accept only types that look similar to own mediatypes
397 pRootFolder
->SetMediaType( aFallBack
);
398 m_bMediaTypeFallbackUsed
= sal_True
;
405 xRootFolder
->removeByName( sMimetype
);
410 void ZipPackage::parseContentType()
412 if ( m_nFormat
== OFOPXML_FORMAT
)
414 const ::rtl::OUString
aContentTypes( RTL_CONSTASCII_USTRINGPARAM ( "[Content_Types].xml" ) );
416 // the content type must exist in OFOPXML format!
417 if ( !xRootFolder
->hasByName( aContentTypes
) )
418 throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX
"Wrong format!" ) ),
419 uno::Reference
< uno::XInterface
>() );
421 uno::Reference
< lang::XUnoTunnel
> xTunnel
;
422 uno::Any aAny
= xRootFolder
->getByName( aContentTypes
);
424 uno::Reference
< io::XActiveDataSink
> xSink( xTunnel
, UNO_QUERY
);
427 uno::Reference
< io::XInputStream
> xInStream
= xSink
->getInputStream();
428 if ( xInStream
.is() )
431 // here aContentTypeInfo[0] - Defaults, and aContentTypeInfo[1] - Overrides
432 uno::Sequence
< uno::Sequence
< beans::StringPair
> > aContentTypeInfo
=
433 ::comphelper::OFOPXMLHelper::ReadContentTypeSequence( xInStream
, xFactory
);
435 if ( aContentTypeInfo
.getLength() != 2 )
436 throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX
) ), uno::Reference
< uno::XInterface
>() );
438 // set the implicit types fist
439 for ( nInd
= 0; nInd
< aContentTypeInfo
[0].getLength(); nInd
++ )
440 pRootFolder
->setChildStreamsTypeByExtension( aContentTypeInfo
[0][nInd
] );
442 // now set the explicit types
443 for ( nInd
= 0; nInd
< aContentTypeInfo
[1].getLength(); nInd
++ )
445 ::rtl::OUString aPath
;
446 if ( aContentTypeInfo
[1][nInd
].First
.toChar() == (sal_Unicode
)'/' )
447 aPath
= aContentTypeInfo
[1][nInd
].First
.copy( 1 );
449 aPath
= aContentTypeInfo
[1][nInd
].First
;
451 if ( aPath
.getLength() && hasByHierarchicalName( aPath
) )
453 uno::Any aIterAny
= getByHierarchicalName( aPath
);
454 uno::Reference
< lang::XUnoTunnel
> xIterTunnel
;
455 aIterAny
>>= xIterTunnel
;
456 sal_Int64 nTest
= xIterTunnel
->getSomething( ZipPackageStream::static_getImplementationId() );
459 // this is a package stream, in OFOPXML format only streams can have mediatype
460 ZipPackageStream
*pStream
= reinterpret_cast < ZipPackageStream
* > ( nTest
);
461 pStream
->SetMediaType( aContentTypeInfo
[1][nInd
].Second
);
468 xRootFolder
->removeByName( aContentTypes
);
470 catch( uno::Exception
& )
472 if ( !bForceRecovery
)
478 void ZipPackage::getZipFileContents()
480 auto_ptr
< ZipEnumeration
> pEnum ( pZipFile
->entries() );
481 ZipPackageStream
*pPkgStream
;
482 ZipPackageFolder
*pPkgFolder
, *pCurrent
;
483 OUString sTemp
, sDirName
;
484 sal_Int32 nOldIndex
, nIndex
, nStreamIndex
;
485 FolderHash::iterator aIter
;
487 while (pEnum
->hasMoreElements())
489 nIndex
= nOldIndex
= 0;
490 pCurrent
= pRootFolder
;
491 const ZipEntry
& rEntry
= *pEnum
->nextElement();
492 const OUString
& rName
= rEntry
.sName
;
494 nStreamIndex
= rName
.lastIndexOf ( '/' );
495 if ( nStreamIndex
!= -1 )
497 sDirName
= rName
.copy ( 0, nStreamIndex
);
498 aIter
= aRecent
.find ( sDirName
);
499 if ( aIter
!= aRecent
.end() )
500 pCurrent
= (*aIter
).second
;
503 if ( pCurrent
== pRootFolder
)
505 while ( (nIndex
= rName
.indexOf('/', nOldIndex
) ) != -1 )
507 sTemp
= rName
.copy ( nOldIndex
, nIndex
- nOldIndex
);
508 if (nIndex
== nOldIndex
)
510 if ( !pCurrent
->hasByName( sTemp
) )
512 pPkgFolder
= new ZipPackageFolder( xFactory
, m_nFormat
, m_bAllowRemoveOnInsert
);
513 pPkgFolder
->setName( sTemp
);
514 pPkgFolder
->doSetParent( pCurrent
, sal_True
);
515 pCurrent
= pPkgFolder
;
518 pCurrent
= pCurrent
->doGetByName(sTemp
).pFolder
;
519 nOldIndex
= nIndex
+1;
521 if ( nStreamIndex
!= -1 && sDirName
.getLength() )
522 aRecent
[ sDirName
] = pCurrent
;
524 if ( rName
.getLength() -1 != nStreamIndex
)
527 sTemp
= rName
.copy( nStreamIndex
, rName
.getLength() - nStreamIndex
);
528 pPkgStream
= new ZipPackageStream( *this, xFactory
, m_bAllowRemoveOnInsert
);
529 pPkgStream
->SetPackageMember( sal_True
);
530 pPkgStream
->setZipEntryOnLoading( rEntry
);
531 pPkgStream
->setName( sTemp
);
532 pPkgStream
->doSetParent( pCurrent
, sal_True
);
536 if ( m_nFormat
== PACKAGE_FORMAT
)
538 else if ( m_nFormat
== OFOPXML_FORMAT
)
543 void SAL_CALL
ZipPackage::initialize( const Sequence
< Any
>& aArguments
)
544 throw(Exception
, RuntimeException
)
546 RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR
, "{ ZipPackage::initialize" );
547 sal_Bool bBadZipFile
= sal_False
, bHaveZipFile
= sal_True
;
548 uno::Reference
< XProgressHandler
> xProgressHandler
;
549 beans::NamedValue aNamedValue
;
551 if ( aArguments
.getLength() )
553 for( int ind
= 0; ind
< aArguments
.getLength(); ind
++ )
556 if ( (aArguments
[ind
] >>= aParamUrl
))
561 sal_Int32 nParam
= aParamUrl
.indexOf( '?' );
564 sURL
= aParamUrl
.copy( 0, nParam
);
565 OUString aParam
= aParamUrl
.copy( nParam
+ 1 );
567 sal_Int32 nIndex
= 0;
570 ::rtl::OUString aCommand
= aParam
.getToken( 0, '&', nIndex
);
571 if ( aCommand
.equals( OUString::createFromAscii( "repairpackage" ) ) )
573 bForceRecovery
= sal_True
;
576 else if ( aCommand
.equals( OUString::createFromAscii( "purezip" ) ) )
578 m_nFormat
= ZIP_FORMAT
;
579 pRootFolder
->setPackageFormat_Impl( m_nFormat
);
582 else if ( aCommand
.equals( OUString::createFromAscii( "ofopxml" ) ) )
584 m_nFormat
= OFOPXML_FORMAT
;
585 pRootFolder
->setPackageFormat_Impl( m_nFormat
);
589 while ( nIndex
>= 0 );
594 Content
aContent ( sURL
, uno::Reference
< XCommandEnvironment
>() );
595 Any aAny
= aContent
.getPropertyValue( OUString::createFromAscii( "Size" ) );
596 sal_uInt64 aSize
= 0;
597 // kind of optimisation: treat empty files as nonexistent files
598 // and write to such files directly. Note that "Size" property is optional.
599 bool bHasSizeProperty
= aAny
>>= aSize
;
600 if( !bHasSizeProperty
|| ( bHasSizeProperty
&& aSize
) )
602 uno::Reference
< XActiveDataSink
> xSink
= new ZipPackageSink
;
603 if (aContent
.openStream ( xSink
) )
604 xContentStream
= xSink
->getInputStream();
607 bHaveZipFile
= sal_False
;
609 catch (com::sun::star::uno::Exception
&)
611 // Exception derived from uno::Exception thrown. This probably
612 // means the file doesn't exist...we'll create it at
613 // commitChanges time
614 bHaveZipFile
= sal_False
;
617 else if ( (aArguments
[ind
] >>= xStream
) )
619 // a writable stream can implement both XStream & XInputStream
620 eMode
= e_IMode_XStream
;
621 xContentStream
= xStream
->getInputStream();
623 else if ( (aArguments
[ind
] >>= xContentStream
) )
625 eMode
= e_IMode_XInputStream
;
627 else if ( ( aArguments
[ind
] >>= aNamedValue
) )
629 if ( aNamedValue
.Name
.equalsAscii( "RepairPackage" ) )
630 aNamedValue
.Value
>>= bForceRecovery
;
631 else if ( aNamedValue
.Name
.equalsAscii( "PackageFormat" ) )
633 // setting this argument to true means Package format
634 // setting it to false means plain Zip format
636 sal_Bool bPackFormat
= sal_True
;
637 aNamedValue
.Value
>>= bPackFormat
;
639 m_nFormat
= ZIP_FORMAT
;
641 pRootFolder
->setPackageFormat_Impl( m_nFormat
);
643 else if ( aNamedValue
.Name
.equalsAscii( "StorageFormat" ) )
645 ::rtl::OUString aFormatName
;
646 aNamedValue
.Value
>>= aFormatName
;
647 if ( aFormatName
.equalsAscii( "PackageFormat" ) )
648 m_nFormat
= PACKAGE_FORMAT
;
649 else if ( aFormatName
.equalsAscii( "ZipFormat" ) )
650 m_nFormat
= ZIP_FORMAT
;
651 else if ( aFormatName
.equalsAscii( "OFOPXMLFormat" ) )
652 m_nFormat
= OFOPXML_FORMAT
;
654 throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX
) ), uno::Reference
< uno::XInterface
>(), 1 );
656 pRootFolder
->setPackageFormat_Impl( m_nFormat
);
658 else if ( aNamedValue
.Name
.equalsAscii( "AllowRemoveOnInsert" ) )
660 aNamedValue
.Value
>>= m_bAllowRemoveOnInsert
;
661 pRootFolder
->setRemoveOnInsertMode_Impl( m_bAllowRemoveOnInsert
);
664 // for now the progress handler is not used, probably it will never be
665 // if ( aNamedValue.Name.equalsAscii( "ProgressHandler" )
669 // The URL is not acceptable
670 throw com::sun::star::uno::Exception ( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX
"Bad arguments." ) ),
671 static_cast < ::cppu::OWeakObject
* > ( this ) );
677 if (xContentStream
.is())
679 // the stream must be seekable, if it is not it will be wrapped
680 xContentStream
= ::comphelper::OSeekableInputWrapper::CheckSeekableCanWrap( xContentStream
, xFactory
);
681 xContentSeek
= uno::Reference
< XSeekable
> ( xContentStream
, UNO_QUERY
);
682 if ( ! xContentSeek
.is() )
683 throw com::sun::star::uno::Exception ( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX
"The package component _requires_ an XSeekable interface!" ) ),
684 static_cast < ::cppu::OWeakObject
* > ( this ) );
686 if ( !xContentSeek
->getLength() )
687 bHaveZipFile
= sal_False
;
690 bHaveZipFile
= sal_False
;
692 catch (com::sun::star::uno::Exception
&)
694 // Exception derived from uno::Exception thrown. This probably
695 // means the file doesn't exist...we'll create it at
696 // commitChanges time
697 bHaveZipFile
= sal_False
;
703 pZipFile
= new ZipFile ( xContentStream
, xFactory
, sal_True
, bForceRecovery
, xProgressHandler
);
704 getZipFileContents();
706 catch ( IOException
& )
708 bBadZipFile
= sal_True
;
710 catch ( ZipException
& )
712 bBadZipFile
= sal_True
;
714 catch ( Exception
& )
716 if( pZipFile
) { delete pZipFile
; pZipFile
= NULL
; }
722 // clean up the memory, and tell the UCB about the error
723 if( pZipFile
) { delete pZipFile
; pZipFile
= NULL
; }
725 throw com::sun::star::packages::zip::ZipIOException (
726 OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX
"Bad Zip File." ) ),
727 static_cast < ::cppu::OWeakObject
* > ( this ) );
732 RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR
, "} ZipPackage::initialize" );
735 Any SAL_CALL
ZipPackage::getByHierarchicalName( const OUString
& aName
)
736 throw(NoSuchElementException
, RuntimeException
)
738 OUString sTemp
, sDirName
;
739 sal_Int32 nOldIndex
, nIndex
, nStreamIndex
;
740 FolderHash::iterator aIter
;
742 if ( (nIndex
= aName
.getLength() ) == 1 && *aName
.getStr() == '/' )
743 return makeAny ( uno::Reference
< XUnoTunnel
> (pRootFolder
) );
746 nStreamIndex
= aName
.lastIndexOf ( '/' );
747 bool bFolder
= nStreamIndex
== nIndex
-1;
748 if ( nStreamIndex
!= -1 )
750 sDirName
= aName
.copy ( 0, nStreamIndex
);
751 aIter
= aRecent
.find ( sDirName
);
752 if ( aIter
!= aRecent
.end() )
756 sal_Int32 nDirIndex
= aName
.lastIndexOf ( '/', nStreamIndex
);
757 sTemp
= aName
.copy ( nDirIndex
== -1 ? 0 : nDirIndex
+1, nStreamIndex
-nDirIndex
-1 );
758 if ( sTemp
== (*aIter
).second
->getName() )
759 return makeAny ( uno::Reference
< XUnoTunnel
> ( (*aIter
).second
) );
761 aRecent
.erase ( aIter
);
765 sTemp
= aName
.copy ( nStreamIndex
+ 1 );
766 if ( (*aIter
).second
->hasByName( sTemp
) )
767 return (*aIter
).second
->getByName( sTemp
);
769 aRecent
.erase( aIter
);
775 if ( pRootFolder
->hasByName ( aName
) )
776 return pRootFolder
->getByName ( aName
);
779 ZipPackageFolder
* pCurrent
= pRootFolder
;
780 ZipPackageFolder
* pPrevious
= NULL
;
781 while ( ( nIndex
= aName
.indexOf('/', nOldIndex
)) != -1)
783 sTemp
= aName
.copy (nOldIndex
, nIndex
- nOldIndex
);
784 if ( nIndex
== nOldIndex
)
786 if ( pCurrent
->hasByName( sTemp
) )
788 pPrevious
= pCurrent
;
789 pCurrent
= pCurrent
->doGetByName(sTemp
).pFolder
;
792 throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX
) ), uno::Reference
< uno::XInterface
>() );
793 nOldIndex
= nIndex
+1;
797 if (nStreamIndex
!= -1 )
798 aRecent
[sDirName
] = pPrevious
;
799 return makeAny ( uno::Reference
< XUnoTunnel
> ( pCurrent
) );
803 sTemp
= aName
.copy( nOldIndex
, aName
.getLength() - nOldIndex
);
804 if ( pCurrent
->hasByName ( sTemp
) )
806 if (nStreamIndex
!= -1 )
807 aRecent
[sDirName
] = pCurrent
;
808 return pCurrent
->getByName( sTemp
);
811 throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX
) ), uno::Reference
< uno::XInterface
>() );
816 sal_Bool SAL_CALL
ZipPackage::hasByHierarchicalName( const OUString
& aName
)
817 throw(RuntimeException
)
819 OUString sTemp
, sDirName
;
820 sal_Int32 nOldIndex
, nIndex
, nStreamIndex
;
821 FolderHash::iterator aIter
;
823 if ( (nIndex
= aName
.getLength() ) == 1 && *aName
.getStr() == '/' )
827 nStreamIndex
= aName
.lastIndexOf ( '/' );
828 bool bFolder
= nStreamIndex
== nIndex
-1;
829 if ( nStreamIndex
!= -1 )
831 sDirName
= aName
.copy ( 0, nStreamIndex
);
832 aIter
= aRecent
.find ( sDirName
);
833 if ( aIter
!= aRecent
.end() )
837 sal_Int32 nDirIndex
= aName
.lastIndexOf ( '/', nStreamIndex
);
838 sTemp
= aName
.copy ( nDirIndex
== -1 ? 0 : nDirIndex
+1, nStreamIndex
-nDirIndex
-1 );
839 if ( sTemp
== (*aIter
).second
->getName() )
842 aRecent
.erase ( aIter
);
846 sTemp
= aName
.copy ( nStreamIndex
+ 1 );
847 if ( (*aIter
).second
->hasByName( sTemp
) )
850 aRecent
.erase( aIter
);
856 if ( pRootFolder
->hasByName ( aName
) )
859 ZipPackageFolder
* pCurrent
= pRootFolder
;
860 ZipPackageFolder
* pPrevious
= NULL
;
862 while ( ( nIndex
= aName
.indexOf('/', nOldIndex
)) != -1)
864 sTemp
= aName
.copy (nOldIndex
, nIndex
- nOldIndex
);
865 if ( nIndex
== nOldIndex
)
867 if ( pCurrent
->hasByName( sTemp
) )
869 pPrevious
= pCurrent
;
870 pCurrent
= pCurrent
->doGetByName( sTemp
).pFolder
;
874 nOldIndex
= nIndex
+1;
878 aRecent
[sDirName
] = pPrevious
;
883 sTemp
= aName
.copy( nOldIndex
, aName
.getLength() - nOldIndex
);
885 if ( pCurrent
->hasByName( sTemp
) )
887 aRecent
[sDirName
] = pCurrent
;
895 // XSingleServiceFactory
896 uno::Reference
< XInterface
> SAL_CALL
ZipPackage::createInstance( )
897 throw(Exception
, RuntimeException
)
899 uno::Reference
< XInterface
> xRef
= *(new ZipPackageStream ( *this, xFactory
, m_bAllowRemoveOnInsert
));
902 uno::Reference
< XInterface
> SAL_CALL
ZipPackage::createInstanceWithArguments( const Sequence
< Any
>& aArguments
)
903 throw(Exception
, RuntimeException
)
905 sal_Bool bArg
= sal_False
;
906 uno::Reference
< XInterface
> xRef
;
907 if ( aArguments
.getLength() )
908 aArguments
[0] >>= bArg
;
910 xRef
= *new ZipPackageFolder ( xFactory
, m_nFormat
, m_bAllowRemoveOnInsert
);
912 xRef
= *new ZipPackageStream ( *this, xFactory
, m_bAllowRemoveOnInsert
);
917 void ZipPackage::WriteMimetypeMagicFile( ZipOutputStream
& aZipOut
)
919 const OUString
sMime ( RTL_CONSTASCII_USTRINGPARAM ( "mimetype" ) );
920 if (xRootFolder
->hasByName( sMime
) )
921 xRootFolder
->removeByName( sMime
);
923 ZipEntry
* pEntry
= new ZipEntry
;
924 sal_Int32 nBufferLength
= pRootFolder
->GetMediaType( ).getLength();
925 OString sMediaType
= OUStringToOString( pRootFolder
->GetMediaType(), RTL_TEXTENCODING_ASCII_US
);
926 Sequence
< sal_Int8
> aType( (sal_Int8
*)sMediaType
.getStr(),
930 pEntry
->sName
= sMime
;
931 pEntry
->nMethod
= STORED
;
932 pEntry
->nSize
= pEntry
->nCompressedSize
= nBufferLength
;
933 pEntry
->nTime
= ZipOutputStream::getCurrentDosTime();
936 aCRC32
.update( aType
);
937 pEntry
->nCrc
= aCRC32
.getValue();
941 vos::ORef
< EncryptionData
> xEmpty
;
942 aZipOut
.putNextEntry( *pEntry
, xEmpty
);
943 aZipOut
.write( aType
, 0, nBufferLength
);
944 aZipOut
.closeEntry();
946 catch ( ::com::sun::star::io::IOException
& r
)
948 VOS_ENSURE( 0, "Error adding mimetype to the ZipOutputStream" );
949 throw WrappedTargetException(
950 OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX
"Error adding mimetype to the ZipOutputStream!" ) ),
951 static_cast < OWeakObject
* > ( this ),
956 void ZipPackage::WriteManifest( ZipOutputStream
& aZipOut
, const vector
< Sequence
< PropertyValue
> >& aManList
)
958 // Write the manifest
959 uno::Reference
< XOutputStream
> xManOutStream
;
960 OUString
sManifestWriter( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.manifest.ManifestWriter" ) );
961 uno::Reference
< XManifestWriter
> xWriter ( xFactory
->createInstance( sManifestWriter
), UNO_QUERY
);
964 ZipEntry
* pEntry
= new ZipEntry
;
965 ZipPackageBuffer
*pBuffer
= new ZipPackageBuffer( n_ConstBufferSize
);
966 xManOutStream
= uno::Reference
< XOutputStream
> (*pBuffer
, UNO_QUERY
);
968 pEntry
->sName
= OUString( RTL_CONSTASCII_USTRINGPARAM ( "META-INF/manifest.xml") );
969 pEntry
->nMethod
= DEFLATED
;
970 pEntry
->nCrc
= pEntry
->nSize
= pEntry
->nCompressedSize
= -1;
971 pEntry
->nTime
= ZipOutputStream::getCurrentDosTime();
973 // Convert vector into a Sequence
974 Sequence
< Sequence
< PropertyValue
> > aManifestSequence ( aManList
.size() );
975 Sequence
< PropertyValue
> * pSequence
= aManifestSequence
.getArray();
976 for (vector
< Sequence
< PropertyValue
> >::const_iterator aIter
= aManList
.begin(), aEnd
= aManList
.end();
978 aIter
++, pSequence
++)
979 *pSequence
= (*aIter
);
980 xWriter
->writeManifestSequence ( xManOutStream
, aManifestSequence
);
982 sal_Int32 nBufferLength
= static_cast < sal_Int32
> ( pBuffer
->getPosition() );
983 pBuffer
->realloc( nBufferLength
);
985 // the manifest.xml is never encrypted - so pass an empty reference
986 vos::ORef
< EncryptionData
> xEmpty
;
987 aZipOut
.putNextEntry( *pEntry
, xEmpty
);
988 aZipOut
.write( pBuffer
->getSequence(), 0, nBufferLength
);
989 aZipOut
.closeEntry();
993 VOS_ENSURE ( 0, "Couldn't get a ManifestWriter!" );
994 IOException aException
;
995 throw WrappedTargetException(
996 OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX
"Couldn't get a ManifestWriter!" ) ),
997 static_cast < OWeakObject
* > ( this ),
998 makeAny( aException
) );
1002 void ZipPackage::WriteContentTypes( ZipOutputStream
& aZipOut
, const vector
< Sequence
< PropertyValue
> >& aManList
)
1004 const OUString
sFullPath ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) );
1005 const OUString
sMediaType ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) );
1007 ZipEntry
* pEntry
= new ZipEntry
;
1008 ZipPackageBuffer
*pBuffer
= new ZipPackageBuffer( n_ConstBufferSize
);
1009 uno::Reference
< io::XOutputStream
> xConTypeOutStream( *pBuffer
, UNO_QUERY
);
1011 pEntry
->sName
= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "[Content_Types].xml") );
1012 pEntry
->nMethod
= DEFLATED
;
1013 pEntry
->nCrc
= pEntry
->nSize
= pEntry
->nCompressedSize
= -1;
1014 pEntry
->nTime
= ZipOutputStream::getCurrentDosTime();
1016 // Convert vector into a Sequence
1017 // TODO/LATER: use Defaulst entries in future
1018 uno::Sequence
< beans::StringPair
> aDefaultsSequence
;
1019 uno::Sequence
< beans::StringPair
> aOverridesSequence( aManList
.size() );
1020 sal_Int32 nSeqLength
= 0;
1021 for ( vector
< uno::Sequence
< beans::PropertyValue
> >::const_iterator aIter
= aManList
.begin(),
1022 aEnd
= aManList
.end();
1026 ::rtl::OUString aPath
;
1027 ::rtl::OUString aType
;
1028 OSL_ENSURE( (*aIter
)[PKG_MNFST_MEDIATYPE
].Name
.equals( sMediaType
) && (*aIter
)[PKG_MNFST_FULLPATH
].Name
.equals( sFullPath
),
1029 "The mediatype sequence format is wrong!\n" );
1030 (*aIter
)[PKG_MNFST_MEDIATYPE
].Value
>>= aType
;
1031 if ( aType
.getLength() )
1033 // only nonempty type makes sence here
1035 (*aIter
)[PKG_MNFST_FULLPATH
].Value
>>= aPath
;
1036 aOverridesSequence
[nSeqLength
-1].First
= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/" ) ) + aPath
;
1037 aOverridesSequence
[nSeqLength
-1].Second
= aType
;
1040 aOverridesSequence
.realloc( nSeqLength
);
1042 ::comphelper::OFOPXMLHelper::WriteContentSequence(
1043 xConTypeOutStream
, aDefaultsSequence
, aOverridesSequence
, xFactory
);
1045 sal_Int32 nBufferLength
= static_cast < sal_Int32
> ( pBuffer
->getPosition() );
1046 pBuffer
->realloc( nBufferLength
);
1048 // there is no encryption in this format currently
1049 vos::ORef
< EncryptionData
> xEmpty
;
1050 aZipOut
.putNextEntry( *pEntry
, xEmpty
);
1051 aZipOut
.write( pBuffer
->getSequence(), 0, nBufferLength
);
1052 aZipOut
.closeEntry();
1055 void ZipPackage::ConnectTo( const uno::Reference
< io::XInputStream
>& xInStream
)
1057 xContentSeek
.set( xInStream
, uno::UNO_QUERY_THROW
);
1058 xContentStream
= xInStream
;
1060 // seek back to the beginning of the temp file so we can read segments from it
1061 xContentSeek
->seek( 0 );
1063 pZipFile
->setInputStream( xContentStream
);
1065 pZipFile
= new ZipFile ( xContentStream
, xFactory
, sal_False
);
1068 uno::Reference
< io::XInputStream
> ZipPackage::writeTempFile()
1070 // In case the target local file does not exist or empty
1071 // write directly to it otherwize create a temporary file to write to.
1072 // If a temporary file is created it is returned back by the method.
1073 // If the data written directly, xComponentStream will be switched here
1075 sal_Bool bUseTemp
= sal_True
;
1076 uno::Reference
< io::XInputStream
> xResult
;
1077 uno::Reference
< io::XInputStream
> xTempIn
;
1079 uno::Reference
< io::XOutputStream
> xTempOut
;
1080 uno::Reference
< io::XActiveDataStreamer
> xSink
;
1082 if ( eMode
== e_IMode_URL
&& !pZipFile
&& isLocalFile_Impl( sURL
) )
1084 xSink
= openOriginalForOutput();
1087 uno::Reference
< io::XStream
> xStr
= xSink
->getStream();
1090 xTempOut
= xStr
->getOutputStream();
1092 bUseTemp
= sal_False
;
1096 else if ( eMode
== e_IMode_XStream
&& !pZipFile
)
1098 // write directly to an empty stream
1099 xTempOut
= xStream
->getOutputStream();
1101 bUseTemp
= sal_False
;
1106 // create temporary file
1107 const OUString
sServiceName ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.TempFile" ) );
1108 uno::Reference
< io::XStream
> xTempFile( xFactory
->createInstance ( sServiceName
), UNO_QUERY_THROW
);
1109 xTempOut
.set( xTempFile
->getOutputStream(), UNO_SET_THROW
);
1110 xTempIn
.set( xTempFile
->getInputStream(), UNO_SET_THROW
);
1113 // Hand it to the ZipOutputStream:
1114 ZipOutputStream
aZipOut ( xTempOut
);
1115 aZipOut
.setMethod(DEFLATED
);
1116 aZipOut
.setLevel(DEFAULT_COMPRESSION
);
1120 if ( m_nFormat
== PACKAGE_FORMAT
)
1122 // Remove the old manifest.xml file as the
1123 // manifest will be re-generated and the
1124 // META-INF directory implicitly created if does not exist
1125 const OUString
sMeta ( RTL_CONSTASCII_USTRINGPARAM ( "META-INF" ) );
1127 if ( xRootFolder
->hasByName( sMeta
) )
1129 const OUString
sManifest (RTL_CONSTASCII_USTRINGPARAM( "manifest.xml") );
1131 uno::Reference
< XUnoTunnel
> xTunnel
;
1132 Any aAny
= xRootFolder
->getByName( sMeta
);
1134 uno::Reference
< XNameContainer
> xMetaInfFolder( xTunnel
, UNO_QUERY
);
1135 if ( xMetaInfFolder
.is() && xMetaInfFolder
->hasByName( sManifest
) )
1136 xMetaInfFolder
->removeByName( sManifest
);
1139 // Write a magic file with mimetype
1140 WriteMimetypeMagicFile( aZipOut
);
1142 else if ( m_nFormat
== OFOPXML_FORMAT
)
1144 // Remove the old [Content_Types].xml file as the
1145 // file will be re-generated
1147 const ::rtl::OUString
aContentTypes( RTL_CONSTASCII_USTRINGPARAM ( "[Content_Types].xml" ) );
1149 if ( xRootFolder
->hasByName( aContentTypes
) )
1150 xRootFolder
->removeByName( aContentTypes
);
1153 // Create a vector to store data for the manifest.xml file
1154 vector
< Sequence
< PropertyValue
> > aManList
;
1156 const OUString
sMediaType ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) );
1157 const OUString
sVersion ( RTL_CONSTASCII_USTRINGPARAM ( "Version" ) );
1158 const OUString
sFullPath ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) );
1160 if ( m_nFormat
== PACKAGE_FORMAT
)
1162 Sequence
< PropertyValue
> aPropSeq ( PKG_SIZE_NOENCR_MNFST
);
1163 aPropSeq
[PKG_MNFST_MEDIATYPE
].Name
= sMediaType
;
1164 aPropSeq
[PKG_MNFST_MEDIATYPE
].Value
<<= pRootFolder
->GetMediaType( );
1165 aPropSeq
[PKG_MNFST_VERSION
].Name
= sVersion
;
1166 aPropSeq
[PKG_MNFST_VERSION
].Value
<<= pRootFolder
->GetVersion( );
1167 aPropSeq
[PKG_MNFST_FULLPATH
].Name
= sFullPath
;
1168 aPropSeq
[PKG_MNFST_FULLPATH
].Value
<<= OUString ( RTL_CONSTASCII_USTRINGPARAM ( "/" ) );
1170 aManList
.push_back( aPropSeq
);
1173 // Get a random number generator and seed it with current timestamp
1174 // This will be used to generate random salt and initialisation vectors
1175 // for encrypted streams
1177 osl_getSystemTime( &aTime
);
1178 rtlRandomPool aRandomPool
= rtl_random_createPool ();
1179 rtl_random_addBytes ( aRandomPool
, &aTime
, 8 );
1182 // call saveContents (it will recursively save sub-directories
1183 OUString aEmptyString
;
1184 pRootFolder
->saveContents( aEmptyString
, aManList
, aZipOut
, aEncryptionKey
, aRandomPool
);
1186 // Clean up random pool memory
1187 rtl_random_destroyPool ( aRandomPool
);
1189 if( bUseManifest
&& m_nFormat
== PACKAGE_FORMAT
)
1191 WriteManifest( aZipOut
, aManList
);
1193 else if( m_nFormat
== OFOPXML_FORMAT
)
1195 WriteContentTypes( aZipOut
, aManList
);
1203 // Update our References to point to the new temp file
1206 // the case when the original contents were written directly
1209 // in case the stream is based on a file it will implement the following interface
1210 // the call should be used to be sure that the contents are written to the file system
1211 uno::Reference
< io::XAsyncOutputMonitor
> asyncOutputMonitor( xTempOut
, uno::UNO_QUERY
);
1212 if ( asyncOutputMonitor
.is() )
1213 asyncOutputMonitor
->waitForCompletion();
1215 // no need to postpone switching to the new stream since the target was written directly
1216 uno::Reference
< io::XInputStream
> xNewStream
;
1217 if ( eMode
== e_IMode_URL
)
1218 xNewStream
= xSink
->getStream()->getInputStream();
1219 else if ( eMode
== e_IMode_XStream
&& xStream
.is() )
1220 xNewStream
= xStream
->getInputStream();
1222 if ( xNewStream
.is() )
1223 ConnectTo( xNewStream
);
1226 catch ( uno::Exception
& )
1230 // no information loss appeares, thus no special handling is required
1231 uno::Any
aCaught( ::cppu::getCaughtException() );
1233 // it is allowed to throw WrappedTargetException
1234 WrappedTargetException aException
;
1235 if ( aCaught
>>= aException
)
1238 throw WrappedTargetException(
1239 OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX
"Problem writing the original content!" ) ),
1240 static_cast < OWeakObject
* > ( this ),
1245 // the document is written directly, although it was empty it is important to notify that the writing has failed
1246 // TODO/LATER: let the package be able to recover in this situation
1247 ::rtl::OUString
aErrTxt( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX
"This package is unusable!" ) );
1248 embed::UseBackupException
aException( aErrTxt
, uno::Reference
< uno::XInterface
>(), ::rtl::OUString() );
1249 throw WrappedTargetException( aErrTxt
,
1250 static_cast < OWeakObject
* > ( this ),
1251 makeAny ( aException
) );
1258 uno::Reference
< XActiveDataStreamer
> ZipPackage::openOriginalForOutput()
1260 // open and truncate the original file
1261 Content
aOriginalContent (sURL
, uno::Reference
< XCommandEnvironment
>() );
1262 uno::Reference
< XActiveDataStreamer
> xSink
= new ActiveDataStreamer
;
1264 if ( eMode
== e_IMode_URL
)
1268 sal_Bool bTruncSuccess
= sal_False
;
1273 sal_Int64 aSize
= 0;
1274 Any aAny
= aOriginalContent
.setPropertyValue( OUString::createFromAscii( "Size" ), makeAny( aSize
) );
1275 if( !( aAny
>>= aDetect
) )
1276 bTruncSuccess
= sal_True
;
1282 if( !bTruncSuccess
)
1284 // the file is not accessible
1285 // just try to write an empty stream to it
1287 uno::Reference
< XInputStream
> xTempIn
= new DummyInputStream
; //uno::Reference< XInputStream >( xTempOut, UNO_QUERY );
1288 aOriginalContent
.writeStream( xTempIn
, sal_True
);
1291 OpenCommandArgument2 aArg
;
1292 aArg
.Mode
= OpenMode::DOCUMENT
;
1293 aArg
.Priority
= 0; // unused
1295 aArg
.Properties
= Sequence
< Property
>( 0 ); // unused
1297 aOriginalContent
.executeCommand( OUString::createFromAscii( "open" ), makeAny( aArg
) );
1301 // seems to be nonlocal file
1302 // temporary file mechanics should be used
1310 void SAL_CALL
ZipPackage::commitChanges()
1311 throw(WrappedTargetException
, RuntimeException
)
1313 // lock the component for the time of commiting
1314 ::osl::MutexGuard
aGuard( m_aMutexHolder
->GetMutex() );
1316 if ( eMode
== e_IMode_XInputStream
)
1318 IOException aException
;
1319 throw WrappedTargetException( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX
"This package is read only!" ) ),
1320 static_cast < OWeakObject
* > ( this ), makeAny ( aException
) );
1323 RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR
, "{ ZipPackage::commitChanges" );
1325 // first the writeTempFile is called, if it returns a stream the stream should be written to the target
1326 // if no stream was returned, the file was written directly, nothing should be done
1328 uno::Reference
< io::XInputStream
> xTempInStream
= writeTempFile();
1329 if ( xTempInStream
.is() )
1331 uno::Reference
< io::XSeekable
> xTempSeek( xTempInStream
, uno::UNO_QUERY_THROW
);
1333 // switch to the new temporary stream only after the transfer
1334 PostinitializationGuard( xTempInStream
, *this );
1336 if ( eMode
== e_IMode_XStream
)
1338 // First truncate our output stream
1339 uno::Reference
< XOutputStream
> xOutputStream
;
1341 // preparation for copy step
1344 xTempSeek
->seek( 0 );
1346 xOutputStream
= xStream
->getOutputStream();
1347 uno::Reference
< XTruncate
> xTruncate ( xOutputStream
, UNO_QUERY
);
1348 if ( !xTruncate
.is() )
1349 throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX
) ), uno::Reference
< uno::XInterface
>() );
1351 // after successful truncation the original file contents are already lost
1352 xTruncate
->truncate();
1354 catch( uno::Exception
& r
)
1356 throw WrappedTargetException( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX
"This package is read only!" ) ),
1357 static_cast < OWeakObject
* > ( this ), makeAny ( r
) );
1362 // then copy the contents of the tempfile to our output stream
1363 ::comphelper::OStorageHelper::CopyInputToOutput( xTempInStream
, xOutputStream
);
1364 xOutputStream
->flush();
1365 uno::Reference
< io::XAsyncOutputMonitor
> asyncOutputMonitor(
1366 xOutputStream
, uno::UNO_QUERY
);
1367 if (asyncOutputMonitor
.is()) {
1368 asyncOutputMonitor
->waitForCompletion();
1371 catch( uno::Exception
& )
1373 // if anything goes wrong in this block the target file becomes corrupted
1374 // so an exception should be thrown as a notification about it
1375 // and the package must disconnect from the stream
1376 DisconnectFromTargetAndThrowException_Impl( xTempInStream
);
1379 else if ( eMode
== e_IMode_URL
)
1381 uno::Reference
< XOutputStream
> aOrigFileStream
;
1382 sal_Bool bCanBeCorrupted
= sal_False
;
1384 if( isLocalFile_Impl( sURL
) )
1386 // write directly in case of local file
1387 uno::Reference
< ::com::sun::star::ucb::XSimpleFileAccess
> xSimpleAccess(
1388 xFactory
->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ),
1390 OSL_ENSURE( xSimpleAccess
.is(), "Can't instatiate SimpleFileAccess service!\n" );
1391 uno::Reference
< io::XTruncate
> xOrigTruncate
;
1392 if ( xSimpleAccess
.is() )
1396 aOrigFileStream
= xSimpleAccess
->openFileWrite( sURL
);
1397 xOrigTruncate
= uno::Reference
< io::XTruncate
>( aOrigFileStream
, uno::UNO_QUERY_THROW
);
1398 // after successful truncation the file is already corrupted
1399 xOrigTruncate
->truncate();
1401 catch( uno::Exception
& )
1405 if( xOrigTruncate
.is() )
1409 ::comphelper::OStorageHelper::CopyInputToOutput( xTempInStream
, aOrigFileStream
);
1410 aOrigFileStream
->closeOutput();
1412 catch( uno::Exception
& )
1415 aOrigFileStream
->closeOutput();
1416 } catch ( uno::Exception
& ) {}
1418 aOrigFileStream
= uno::Reference
< XOutputStream
>();
1419 // the original file can already be corrupted
1420 bCanBeCorrupted
= sal_True
;
1425 if( !aOrigFileStream
.is() )
1429 uno::Reference
< XPropertySet
> xPropSet ( xTempInStream
, UNO_QUERY
);
1430 OSL_ENSURE( xPropSet
.is(), "This is a temporary file that must implement XPropertySet!\n" );
1431 if ( !xPropSet
.is() )
1432 throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX
) ), uno::Reference
< uno::XInterface
>() );
1434 OUString sTargetFolder
= sURL
.copy ( 0, sURL
.lastIndexOf ( static_cast < sal_Unicode
> ( '/' ) ) );
1435 Content
aContent ( sTargetFolder
, uno::Reference
< XCommandEnvironment
> () );
1438 Any aAny
= xPropSet
->getPropertyValue ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Uri" ) ) );
1442 aInfo
.NameClash
= NameClash::OVERWRITE
;
1443 aInfo
.MoveData
= sal_False
;
1444 aInfo
.SourceURL
= sTempURL
;
1445 aInfo
.NewTitle
= rtl::Uri::decode ( sURL
.copy ( 1 + sURL
.lastIndexOf ( static_cast < sal_Unicode
> ( '/' ) ) ),
1446 rtl_UriDecodeWithCharset
,
1447 RTL_TEXTENCODING_UTF8
);
1450 // if the file is still not corrupted, it can become after the next step
1451 aContent
.executeCommand ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "transfer" ) ), aAny
);
1453 catch (::com::sun::star::uno::Exception
& r
)
1455 if ( bCanBeCorrupted
)
1456 DisconnectFromTargetAndThrowException_Impl( xTempInStream
);
1458 throw WrappedTargetException(
1459 OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX
"This package may be read only!" ) ),
1460 static_cast < OWeakObject
* > ( this ),
1467 // after successful storing it can be set to false
1468 m_bMediaTypeFallbackUsed
= sal_False
;
1470 RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR
, "} ZipPackage::commitChanges" );
1473 void ZipPackage::DisconnectFromTargetAndThrowException_Impl( const uno::Reference
< io::XInputStream
>& xTempStream
)
1475 xStream
= uno::Reference
< io::XStream
>( xTempStream
, uno::UNO_QUERY
);
1477 eMode
= e_IMode_XStream
;
1479 eMode
= e_IMode_XInputStream
;
1481 ::rtl::OUString aTempURL
;
1483 uno::Reference
< beans::XPropertySet
> xTempFile( xTempStream
, uno::UNO_QUERY_THROW
);
1484 uno::Any aUrl
= xTempFile
->getPropertyValue( ::rtl::OUString::createFromAscii( "Uri" ) );
1486 xTempFile
->setPropertyValue( ::rtl::OUString::createFromAscii( "RemoveFile" ),
1487 uno::makeAny( sal_False
) );
1489 catch ( uno::Exception
& )
1491 OSL_ENSURE( sal_False
, "These calls are pretty simple, they should not fail!\n" );
1494 ::rtl::OUString
aErrTxt( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX
"This package is read only!" ) );
1495 embed::UseBackupException
aException( aErrTxt
, uno::Reference
< uno::XInterface
>(), aTempURL
);
1496 throw WrappedTargetException( aErrTxt
,
1497 static_cast < OWeakObject
* > ( this ),
1498 makeAny ( aException
) );
1501 sal_Bool SAL_CALL
ZipPackage::hasPendingChanges( )
1502 throw(RuntimeException
)
1506 Sequence
< ElementChange
> SAL_CALL
ZipPackage::getPendingChanges( )
1507 throw(RuntimeException
)
1509 return Sequence
< ElementChange
> ();
1513 * Function to create a new component instance; is needed by factory helper implementation.
1514 * @param xMgr service manager to if the components needs other component instances
1516 uno::Reference
< XInterface
>SAL_CALL
ZipPackage_createInstance(
1517 const uno::Reference
< XMultiServiceFactory
> & xMgr
)
1519 return uno::Reference
< XInterface
>( *new ZipPackage(xMgr
) );
1522 OUString
ZipPackage::static_getImplementationName()
1524 return OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.comp.ZipPackage" ) );
1527 Sequence
< OUString
> ZipPackage::static_getSupportedServiceNames()
1529 Sequence
< OUString
> aNames(1);
1530 aNames
[0] = OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.Package" ) );
1533 sal_Bool SAL_CALL
ZipPackage::static_supportsService( OUString
const & rServiceName
)
1535 return rServiceName
== getSupportedServiceNames()[0];
1538 OUString
ZipPackage::getImplementationName()
1539 throw (RuntimeException
)
1541 return static_getImplementationName();
1544 Sequence
< OUString
> ZipPackage::getSupportedServiceNames()
1545 throw (RuntimeException
)
1547 return static_getSupportedServiceNames();
1549 sal_Bool SAL_CALL
ZipPackage::supportsService( OUString
const & rServiceName
)
1550 throw (RuntimeException
)
1552 return static_supportsService ( rServiceName
);
1554 uno::Reference
< XSingleServiceFactory
> ZipPackage::createServiceFactory( uno::Reference
< XMultiServiceFactory
> const & rServiceFactory
)
1556 return cppu::createSingleFactory (rServiceFactory
,
1557 static_getImplementationName(),
1558 ZipPackage_createInstance
,
1559 static_getSupportedServiceNames());
1563 Sequence
< sal_Int8
> ZipPackage::getUnoTunnelImplementationId( void )
1564 throw (RuntimeException
)
1566 static ::cppu::OImplementationId
* pId
= 0;
1569 ::osl::MutexGuard
aGuard( ::osl::Mutex::getGlobalMutex() );
1572 static ::cppu::OImplementationId aId
;
1576 return pId
->getImplementationId();
1579 sal_Int64 SAL_CALL
ZipPackage::getSomething( const Sequence
< sal_Int8
>& aIdentifier
)
1580 throw(RuntimeException
)
1582 if (aIdentifier
.getLength() == 16 && 0 == rtl_compareMemory(getUnoTunnelImplementationId().getConstArray(), aIdentifier
.getConstArray(), 16 ) )
1583 return reinterpret_cast < sal_Int64
> ( this );
1587 uno::Reference
< XPropertySetInfo
> SAL_CALL
ZipPackage::getPropertySetInfo( )
1588 throw(RuntimeException
)
1590 return uno::Reference
< XPropertySetInfo
> ();
1592 void SAL_CALL
ZipPackage::setPropertyValue( const OUString
& aPropertyName
, const Any
& aValue
)
1593 throw(UnknownPropertyException
, PropertyVetoException
, IllegalArgumentException
, WrappedTargetException
, RuntimeException
)
1595 if ( m_nFormat
!= PACKAGE_FORMAT
)
1596 throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX
) ), uno::Reference
< uno::XInterface
>() );
1598 if (aPropertyName
.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("HasEncryptedEntries") )
1599 ||aPropertyName
.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("MediaTypeFallbackUsed") ) )
1600 throw PropertyVetoException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX
) ), uno::Reference
< uno::XInterface
>() );
1601 else if (aPropertyName
.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("EncryptionKey") ) )
1603 if (!( aValue
>>= aEncryptionKey
) )
1604 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX
) ), uno::Reference
< uno::XInterface
>(), 2 );
1606 else if (aPropertyName
.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("UseManifest") ) )
1608 if (!( aValue
>>= bUseManifest
) )
1609 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX
) ), uno::Reference
< uno::XInterface
>(), 2 );
1612 throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX
) ), uno::Reference
< uno::XInterface
>() );
1614 Any SAL_CALL
ZipPackage::getPropertyValue( const OUString
& PropertyName
)
1615 throw(UnknownPropertyException
, WrappedTargetException
, RuntimeException
)
1617 // TODO/LATER: Activate the check when zip-ucp is ready
1618 // if ( m_nFormat != PACKAGE_FORMAT )
1619 // throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1622 if (PropertyName
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "EncryptionKey" ) ) )
1624 aAny
<<= aEncryptionKey
;
1627 else if (PropertyName
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "HasEncryptedEntries" ) ) )
1629 aAny
<<= bHasEncryptedEntries
;
1632 else if (PropertyName
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "UseManifest" ) ) )
1634 aAny
<<= bUseManifest
;
1637 else if (PropertyName
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "MediaTypeFallbackUsed" ) ) )
1639 aAny
<<= m_bMediaTypeFallbackUsed
;
1642 throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX
) ), uno::Reference
< uno::XInterface
>() );
1644 void SAL_CALL
ZipPackage::addPropertyChangeListener( const OUString
& /*aPropertyName*/, const uno::Reference
< XPropertyChangeListener
>& /*xListener*/ )
1645 throw(UnknownPropertyException
, WrappedTargetException
, RuntimeException
)
1648 void SAL_CALL
ZipPackage::removePropertyChangeListener( const OUString
& /*aPropertyName*/, const uno::Reference
< XPropertyChangeListener
>& /*aListener*/ )
1649 throw(UnknownPropertyException
, WrappedTargetException
, RuntimeException
)
1652 void SAL_CALL
ZipPackage::addVetoableChangeListener( const OUString
& /*PropertyName*/, const uno::Reference
< XVetoableChangeListener
>& /*aListener*/ )
1653 throw(UnknownPropertyException
, WrappedTargetException
, RuntimeException
)
1656 void SAL_CALL
ZipPackage::removeVetoableChangeListener( const OUString
& /*PropertyName*/, const uno::Reference
< XVetoableChangeListener
>& /*aListener*/ )
1657 throw(UnknownPropertyException
, WrappedTargetException
, RuntimeException
)