1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/lang/DisposedException.hpp>
21 #include <com/sun/star/lang/IllegalArgumentException.hpp>
22 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
23 #include <com/sun/star/io/XActiveDataSink.hpp>
24 #include <com/sun/star/io/XStream.hpp>
25 #include <com/sun/star/io/XSeekable.hpp>
26 #include <comphelper/processfactory.hxx>
27 #include <zipfileaccess.hxx>
28 #include <ZipEnumeration.hxx>
29 #include <ZipPackageSink.hxx>
30 #include <EncryptionData.hxx>
32 #include <ucbhelper/content.hxx>
33 #include <rtl/ref.hxx>
38 using namespace ::com::sun::star
;
40 // ----------------------------------------------------------------
41 OZipFileAccess::OZipFileAccess( const uno::Reference
< uno::XComponentContext
>& rxContext
)
42 : m_aMutexHolder( new SotMutexHolder
)
43 , m_xContext( rxContext
)
45 , m_pListenersContainer( NULL
)
46 , m_bDisposed( sal_False
)
48 if ( !rxContext
.is() )
49 throw uno::RuntimeException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
52 // ----------------------------------------------------------------
53 OZipFileAccess::~OZipFileAccess()
56 ::osl::MutexGuard
aGuard( m_aMutexHolder
->GetMutex() );
60 m_refCount
++; // dispose will use refcounting so the further distruction must be avoided
62 } catch( uno::Exception
& )
68 // ----------------------------------------------------------------
69 uno::Sequence
< OUString
> OZipFileAccess::GetPatternsFromString_Impl( const OUString
& aString
)
71 if ( aString
.isEmpty() )
72 return uno::Sequence
< OUString
>();
74 uno::Sequence
< OUString
> aPattern( 1 );
77 const sal_Unicode
* pString
= aString
.getStr();
80 if ( *pString
== (sal_Unicode
)'\\' )
84 if ( *pString
== (sal_Unicode
)'\\' )
86 aPattern
[nInd
] += OUString::valueOf( (sal_Unicode
)'\\' );
89 else if ( *pString
== (sal_Unicode
)'*' )
91 aPattern
[nInd
] += OUString::valueOf( (sal_Unicode
)'*' );
96 OSL_FAIL( "The backslash is not guarded!\n" );
97 aPattern
[nInd
] += OUString::valueOf( (sal_Unicode
)'\\' );
100 else if ( *pString
== (sal_Unicode
)'*' )
102 aPattern
.realloc( ( ++nInd
) + 1 );
107 aPattern
[nInd
] += OUString::valueOf( *pString
);
115 // ----------------------------------------------------------------
116 sal_Bool
OZipFileAccess::StringGoodForPattern_Impl( const OUString
& aString
,
117 const uno::Sequence
< OUString
>& aPattern
)
119 sal_Int32 nInd
= aPattern
.getLength() - 1;
125 if ( aPattern
[0].isEmpty() )
128 return aString
.equals( aPattern
[0] );
131 sal_Int32 nBeginInd
= aPattern
[0].getLength();
132 sal_Int32 nEndInd
= aString
.getLength() - aPattern
[nInd
].getLength();
133 if ( nEndInd
>= nBeginInd
134 && ( nEndInd
== aString
.getLength() || aString
.copy( nEndInd
).equals( aPattern
[nInd
] ) )
135 && ( nBeginInd
== 0 || aString
.copy( 0, nBeginInd
).equals( aPattern
[0] ) ) )
137 for ( sal_Int32 nCurInd
= aPattern
.getLength() - 2; nCurInd
> 0; nCurInd
-- )
139 if ( aPattern
[nCurInd
].isEmpty() )
142 if ( nEndInd
== nBeginInd
)
145 // check that search does not use nEndInd position
146 sal_Int32 nLastInd
= aString
.lastIndexOf( aPattern
[nCurInd
], nEndInd
- 1 );
148 if ( nLastInd
== -1 )
151 if ( nLastInd
< nBeginInd
)
164 // ----------------------------------------------------------------
165 void SAL_CALL
OZipFileAccess::initialize( const uno::Sequence
< uno::Any
>& aArguments
)
166 throw ( uno::Exception
,
167 uno::RuntimeException
)
169 ::osl::MutexGuard
aGuard( m_aMutexHolder
->GetMutex() );
172 throw lang::DisposedException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
175 throw uno::RuntimeException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() ); // initialization is allowed only one time
177 if ( !aArguments
.getLength() )
178 throw lang::IllegalArgumentException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>(), 1 );
180 OSL_ENSURE( aArguments
.getLength() == 1, "Too many arguments are provided, only the first one will be used!\n" );
183 uno::Reference
< io::XStream
> xStream
;
184 uno::Reference
< io::XSeekable
> xSeekable
;
186 if ( ( aArguments
[0] >>= aParamURL
) )
188 ::ucbhelper::Content
aContent(
190 uno::Reference
< ::com::sun::star::ucb::XCommandEnvironment
>(),
192 uno::Reference
< io::XActiveDataSink
> xSink
= new ZipPackageSink
;
193 if ( aContent
.openStream ( xSink
) )
195 m_xContentStream
= xSink
->getInputStream();
196 xSeekable
= uno::Reference
< io::XSeekable
>( m_xContentStream
, uno::UNO_QUERY
);
199 else if ( (aArguments
[0] >>= xStream
) )
201 // a writable stream can implement both XStream & XInputStream
202 m_xContentStream
= xStream
->getInputStream();
203 xSeekable
= uno::Reference
< io::XSeekable
>( xStream
, uno::UNO_QUERY
);
205 else if ( !( aArguments
[0] >>= m_xContentStream
) )
207 xSeekable
= uno::Reference
< io::XSeekable
>( m_xContentStream
, uno::UNO_QUERY
);
210 throw lang::IllegalArgumentException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>(), 1 );
212 if ( !m_xContentStream
.is() )
213 throw io::IOException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
215 if ( !xSeekable
.is() )
217 // TODO: after fwkbugfix02 is integrated a helper class can be used to make the stream seekable
218 throw io::IOException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
221 // TODO: in case xSeekable is implemented on separated XStream implementation a wrapper is required
222 m_pZipFile
= new ZipFile(
229 // ----------------------------------------------------------------
230 uno::Any SAL_CALL
OZipFileAccess::getByName( const OUString
& aName
)
231 throw ( container::NoSuchElementException
,
232 lang::WrappedTargetException
,
233 uno::RuntimeException
)
235 ::osl::MutexGuard
aGuard( m_aMutexHolder
->GetMutex() );
238 throw lang::DisposedException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
241 throw io::NotConnectedException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
243 EntryHash::iterator aIter
= m_pZipFile
->GetEntryHash().find( aName
);
244 if ( aIter
== m_pZipFile
->GetEntryHash().end() )
245 throw container::NoSuchElementException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
247 uno::Reference
< io::XInputStream
> xEntryStream( m_pZipFile
->getDataStream( (*aIter
).second
,
248 ::rtl::Reference
< EncryptionData
>(),
252 if ( !xEntryStream
.is() )
253 throw uno::RuntimeException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
255 return uno::makeAny ( xEntryStream
);
258 // ----------------------------------------------------------------
259 uno::Sequence
< OUString
> SAL_CALL
OZipFileAccess::getElementNames()
260 throw ( uno::RuntimeException
)
262 ::osl::MutexGuard
aGuard( m_aMutexHolder
->GetMutex() );
265 throw lang::DisposedException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
268 throw io::NotConnectedException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
270 uno::Sequence
< OUString
> aNames( m_pZipFile
->GetEntryHash().size() );
273 for ( EntryHash::iterator aIter
= m_pZipFile
->GetEntryHash().begin(); aIter
!= m_pZipFile
->GetEntryHash().end(); ++aIter
)
275 if ( aNames
.getLength() < ++nLen
)
277 OSL_FAIL( "The size must be the same!\n" );
278 aNames
.realloc( nLen
);
281 aNames
[nLen
-1] = (*aIter
).second
.sPath
;
284 if ( aNames
.getLength() != nLen
)
286 OSL_FAIL( "The size must be the same!\n" );
287 aNames
.realloc( nLen
);
293 // ----------------------------------------------------------------
294 sal_Bool SAL_CALL
OZipFileAccess::hasByName( const OUString
& aName
)
295 throw (uno::RuntimeException
)
297 ::osl::MutexGuard
aGuard( m_aMutexHolder
->GetMutex() );
300 throw lang::DisposedException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
303 throw io::NotConnectedException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
305 EntryHash::iterator aIter
= m_pZipFile
->GetEntryHash().find( aName
);
307 return ( aIter
!= m_pZipFile
->GetEntryHash().end() );
310 // ----------------------------------------------------------------
311 uno::Type SAL_CALL
OZipFileAccess::getElementType()
312 throw ( uno::RuntimeException
)
314 ::osl::MutexGuard
aGuard( m_aMutexHolder
->GetMutex() );
317 throw lang::DisposedException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
320 throw io::NotConnectedException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
322 return getCppuType( ( const uno::Reference
< io::XInputStream
>* )NULL
);
325 // ----------------------------------------------------------------
326 sal_Bool SAL_CALL
OZipFileAccess::hasElements()
327 throw ( uno::RuntimeException
)
329 ::osl::MutexGuard
aGuard( m_aMutexHolder
->GetMutex() );
332 throw lang::DisposedException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
335 throw io::NotConnectedException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
337 return ( m_pZipFile
->GetEntryHash().size() != 0 );
341 // ----------------------------------------------------------------
342 uno::Reference
< io::XInputStream
> SAL_CALL
OZipFileAccess::getStreamByPattern( const OUString
& aPatternString
)
343 throw ( container::NoSuchElementException
,
345 uno::RuntimeException
)
347 ::osl::MutexGuard
aGuard( m_aMutexHolder
->GetMutex() );
350 throw lang::DisposedException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
353 throw io::NotConnectedException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
355 // Code to compare strings by patterns
356 uno::Sequence
< OUString
> aPattern
= GetPatternsFromString_Impl( aPatternString
);
358 for ( EntryHash::iterator aIter
= m_pZipFile
->GetEntryHash().begin(); aIter
!= m_pZipFile
->GetEntryHash().end(); ++aIter
)
360 if ( StringGoodForPattern_Impl( (*aIter
).second
.sPath
, aPattern
) )
362 uno::Reference
< io::XInputStream
> xEntryStream( m_pZipFile
->getDataStream( (*aIter
).second
,
363 ::rtl::Reference
< EncryptionData
>(),
367 if ( !xEntryStream
.is() )
368 throw uno::RuntimeException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
373 throw container::NoSuchElementException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
377 // ----------------------------------------------------------------
378 void SAL_CALL
OZipFileAccess::dispose()
379 throw ( uno::RuntimeException
)
381 ::osl::MutexGuard
aGuard( m_aMutexHolder
->GetMutex() );
384 throw lang::DisposedException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
386 if ( m_pListenersContainer
)
388 lang::EventObject
aSource( static_cast< ::cppu::OWeakObject
* >(this) );
389 m_pListenersContainer
->disposeAndClear( aSource
);
390 delete m_pListenersContainer
;
391 m_pListenersContainer
= NULL
;
400 if ( m_xContentStream
.is() )
402 m_xContentStream
->closeInput();
403 } catch( uno::Exception
& )
406 m_bDisposed
= sal_True
;
409 // ----------------------------------------------------------------
410 void SAL_CALL
OZipFileAccess::addEventListener( const uno::Reference
< lang::XEventListener
>& xListener
)
411 throw ( uno::RuntimeException
)
413 ::osl::MutexGuard
aGuard( m_aMutexHolder
->GetMutex() );
416 throw lang::DisposedException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
418 if ( !m_pListenersContainer
)
419 m_pListenersContainer
= new ::cppu::OInterfaceContainerHelper( m_aMutexHolder
->GetMutex() );
420 m_pListenersContainer
->addInterface( xListener
);
423 // ----------------------------------------------------------------
424 void SAL_CALL
OZipFileAccess::removeEventListener( const uno::Reference
< lang::XEventListener
>& xListener
)
425 throw ( uno::RuntimeException
)
427 ::osl::MutexGuard
aGuard( m_aMutexHolder
->GetMutex() );
430 throw lang::DisposedException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
432 if ( m_pListenersContainer
)
433 m_pListenersContainer
->removeInterface( xListener
);
436 //-------------------------------------------------------------------------
437 uno::Sequence
< OUString
> SAL_CALL
OZipFileAccess::impl_staticGetSupportedServiceNames()
439 uno::Sequence
< OUString
> aRet(2);
440 aRet
[0] = "com.sun.star.packages.zip.ZipFileAccess";
441 aRet
[1] = "com.sun.star.comp.packages.zip.ZipFileAccess";
445 //-------------------------------------------------------------------------
446 OUString SAL_CALL
OZipFileAccess::impl_staticGetImplementationName()
448 return OUString("com.sun.star.comp.package.zip.ZipFileAccess");
451 //-------------------------------------------------------------------------
452 uno::Reference
< uno::XInterface
> SAL_CALL
OZipFileAccess::impl_staticCreateSelfInstance(
453 const uno::Reference
< lang::XMultiServiceFactory
>& rxMSF
)
455 return uno::Reference
< uno::XInterface
>( *new OZipFileAccess( comphelper::getComponentContext(rxMSF
) ) );
458 //-------------------------------------------------------------------------
459 OUString SAL_CALL
OZipFileAccess::getImplementationName()
460 throw ( uno::RuntimeException
)
462 return impl_staticGetImplementationName();
465 //-------------------------------------------------------------------------
466 sal_Bool SAL_CALL
OZipFileAccess::supportsService( const OUString
& ServiceName
)
467 throw ( uno::RuntimeException
)
469 uno::Sequence
< OUString
> aSeq
= impl_staticGetSupportedServiceNames();
471 for ( sal_Int32 nInd
= 0; nInd
< aSeq
.getLength(); nInd
++ )
472 if ( ServiceName
== aSeq
[nInd
] )
478 //-------------------------------------------------------------------------
479 uno::Sequence
< OUString
> SAL_CALL
OZipFileAccess::getSupportedServiceNames()
480 throw ( uno::RuntimeException
)
482 return impl_staticGetSupportedServiceNames();
485 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */