update credits
[LibreOffice.git] / package / source / zippackage / zipfileaccess.cxx
blob5f30ee9b723304ae3e3acd8c0e071c4513b97a08
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
35 #include <memory>
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 )
44 , m_pZipFile( NULL )
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() );
57 if ( !m_bDisposed )
59 try {
60 m_refCount++; // dispose will use refcounting so the further distruction must be avoided
61 dispose();
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 );
75 sal_Int32 nInd = 0;
77 const sal_Unicode* pString = aString.getStr();
78 while( *pString )
80 if ( *pString == (sal_Unicode)'\\' )
82 pString++;
84 if ( *pString == (sal_Unicode)'\\' )
86 aPattern[nInd] += OUString::valueOf( (sal_Unicode)'\\' );
87 pString++;
89 else if ( *pString == (sal_Unicode)'*' )
91 aPattern[nInd] += OUString::valueOf( (sal_Unicode)'*' );
92 pString++;
94 else
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 );
103 pString++;
105 else
107 aPattern[nInd] += OUString::valueOf( *pString );
108 pString++;
112 return aPattern;
115 // ----------------------------------------------------------------
116 sal_Bool OZipFileAccess::StringGoodForPattern_Impl( const OUString& aString,
117 const uno::Sequence< OUString >& aPattern )
119 sal_Int32 nInd = aPattern.getLength() - 1;
120 if ( nInd < 0 )
121 return sal_False;
123 if ( nInd == 0 )
125 if ( aPattern[0].isEmpty() )
126 return sal_True;
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() )
140 continue;
142 if ( nEndInd == nBeginInd )
143 return sal_False;
145 // check that search does not use nEndInd position
146 sal_Int32 nLastInd = aString.lastIndexOf( aPattern[nCurInd], nEndInd - 1 );
148 if ( nLastInd == -1 )
149 return sal_False;
151 if ( nLastInd < nBeginInd )
152 return sal_False;
154 nEndInd = nLastInd;
157 return sal_True;
160 return sal_False;
163 // XInitialization
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() );
171 if ( m_bDisposed )
172 throw lang::DisposedException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
174 if ( m_pZipFile )
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" );
182 OUString aParamURL;
183 uno::Reference< io::XStream > xStream;
184 uno::Reference< io::XSeekable > xSeekable;
186 if ( ( aArguments[0] >>= aParamURL ) )
188 ::ucbhelper::Content aContent(
189 aParamURL,
190 uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >(),
191 m_xContext );
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 );
209 else
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(
223 m_xContentStream,
224 m_xContext,
225 sal_True );
228 // XNameAccess
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() );
237 if ( m_bDisposed )
238 throw lang::DisposedException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
240 if ( !m_pZipFile )
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 >(),
249 sal_False,
250 m_aMutexHolder ) );
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() );
264 if ( m_bDisposed )
265 throw lang::DisposedException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
267 if ( !m_pZipFile )
268 throw io::NotConnectedException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
270 uno::Sequence< OUString > aNames( m_pZipFile->GetEntryHash().size() );
271 sal_Int32 nLen = 0;
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 );
290 return aNames;
293 // ----------------------------------------------------------------
294 sal_Bool SAL_CALL OZipFileAccess::hasByName( const OUString& aName )
295 throw (uno::RuntimeException)
297 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
299 if ( m_bDisposed )
300 throw lang::DisposedException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
302 if ( !m_pZipFile )
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() );
316 if ( m_bDisposed )
317 throw lang::DisposedException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
319 if ( !m_pZipFile )
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() );
331 if ( m_bDisposed )
332 throw lang::DisposedException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
334 if ( !m_pZipFile )
335 throw io::NotConnectedException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
337 return ( m_pZipFile->GetEntryHash().size() != 0 );
340 // XZipFileAccess
341 // ----------------------------------------------------------------
342 uno::Reference< io::XInputStream > SAL_CALL OZipFileAccess::getStreamByPattern( const OUString& aPatternString )
343 throw ( container::NoSuchElementException,
344 io::IOException,
345 uno::RuntimeException )
347 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
349 if ( m_bDisposed )
350 throw lang::DisposedException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
352 if ( !m_pZipFile )
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 >(),
364 sal_False,
365 m_aMutexHolder ) );
367 if ( !xEntryStream.is() )
368 throw uno::RuntimeException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
369 return xEntryStream;
373 throw container::NoSuchElementException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
376 // XComponent
377 // ----------------------------------------------------------------
378 void SAL_CALL OZipFileAccess::dispose()
379 throw ( uno::RuntimeException )
381 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
383 if ( m_bDisposed )
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;
394 if ( m_pZipFile )
396 delete m_pZipFile;
397 m_pZipFile = NULL;
400 if ( m_xContentStream.is() )
401 try {
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() );
415 if ( m_bDisposed )
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() );
429 if ( m_bDisposed )
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";
442 return aRet;
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] )
473 return sal_True;
475 return sal_False;
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: */