1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_package.hxx"
26 #include <com/sun/star/lang/DisposedException.hpp>
27 #ifndef _COM_SUN_STAR_LANG_INVALIDARGUMENTEXCEPTION_HPP_
28 #include <com/sun/star/lang/IllegalArgumentException.hpp>
29 #endif
30 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
31 #include <com/sun/star/io/XActiveDataSink.hpp>
32 #include <com/sun/star/io/XStream.hpp>
33 #include <com/sun/star/io/XSeekable.hpp>
34
35 #include <zipfileaccess.hxx>
36 #include <ZipEnumeration.hxx>
37 #include <ZipPackageSink.hxx>
38 #include <EncryptionData.hxx>
39
40 #include <ucbhelper/content.hxx>
41 #include <rtl/ref.hxx>
42
43 #include <memory>
44
45
46 using namespace ::com::sun::star;
47
48 // ----------------------------------------------------------------
OZipFileAccess(const uno::Reference<lang::XMultiServiceFactory> & xFactory)49 OZipFileAccess::OZipFileAccess( const uno::Reference< lang::XMultiServiceFactory >& xFactory )
50 : m_aMutexHolder( new SotMutexHolder )
51 , m_xFactory( xFactory )
52 , m_pZipFile( NULL )
53 , m_pListenersContainer( NULL )
54 , m_bDisposed( sal_False )
55 {
56 if ( !xFactory.is() )
57 throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
58 }
59
60 // ----------------------------------------------------------------
~OZipFileAccess()61 OZipFileAccess::~OZipFileAccess()
62 {
63 {
64 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
65 if ( !m_bDisposed )
66 {
67 try {
68 m_refCount++; // dispose will use refcounting so the further destruction must be avoided
69 dispose();
70 } catch( uno::Exception& )
71 {}
72 }
73 }
74 }
75
76 // ----------------------------------------------------------------
GetPatternsFromString_Impl(const::rtl::OUString & aString)77 uno::Sequence< ::rtl::OUString > OZipFileAccess::GetPatternsFromString_Impl( const ::rtl::OUString& aString )
78 {
79 if ( !aString.getLength() )
80 return uno::Sequence< ::rtl::OUString >();
81
82 uno::Sequence< ::rtl::OUString > aPattern( 1 );
83 sal_Int32 nInd = 0;
84
85 const sal_Unicode* pString = aString.getStr();
86 while( *pString )
87 {
88 if ( *pString == (sal_Unicode)'\\' )
89 {
90 pString++;
91
92 if ( *pString == (sal_Unicode)'\\' )
93 {
94 aPattern[nInd] += ::rtl::OUString::valueOf( (sal_Unicode)'\\' );
95 pString++;
96 }
97 else if ( *pString == (sal_Unicode)'*' )
98 {
99 aPattern[nInd] += ::rtl::OUString::valueOf( (sal_Unicode)'*' );
100 pString++;
101 }
102 else
103 {
104 OSL_ENSURE( sal_False, "The backslash is not guarded!\n" );
105 aPattern[nInd] += ::rtl::OUString::valueOf( (sal_Unicode)'\\' );
106 }
107 }
108 else if ( *pString == (sal_Unicode)'*' )
109 {
110 aPattern.realloc( ( ++nInd ) + 1 );
111 pString++;
112 }
113 else
114 {
115 aPattern[nInd] += ::rtl::OUString::valueOf( *pString );
116 pString++;
117 }
118 }
119
120 return aPattern;
121 }
122
123 // ----------------------------------------------------------------
StringGoodForPattern_Impl(const::rtl::OUString & aString,const uno::Sequence<::rtl::OUString> & aPattern)124 sal_Bool OZipFileAccess::StringGoodForPattern_Impl( const ::rtl::OUString& aString,
125 const uno::Sequence< ::rtl::OUString >& aPattern )
126 {
127 sal_Int32 nInd = aPattern.getLength() - 1;
128 if ( nInd < 0 )
129 return sal_False;
130
131 if ( nInd == 0 )
132 {
133 if ( !aPattern[0].getLength() )
134 return sal_True;
135
136 return aString.equals( aPattern[0] );
137 }
138
139 sal_Int32 nBeginInd = aPattern[0].getLength();
140 sal_Int32 nEndInd = aString.getLength() - aPattern[nInd].getLength();
141 if ( nEndInd >= nBeginInd
142 && ( nEndInd == aString.getLength() || aString.copy( nEndInd ).equals( aPattern[nInd] ) )
143 && ( nBeginInd == 0 || aString.copy( 0, nBeginInd ).equals( aPattern[0] ) ) )
144 {
145 for ( sal_Int32 nCurInd = aPattern.getLength() - 2; nCurInd > 0; nCurInd-- )
146 {
147 if ( !aPattern[nCurInd].getLength() )
148 continue;
149
150 if ( nEndInd == nBeginInd )
151 return sal_False;
152
153 // check that search does not use nEndInd position
154 sal_Int32 nLastInd = aString.lastIndexOf( aPattern[nCurInd], nEndInd - 1 );
155
156 if ( nLastInd == -1 )
157 return sal_False;
158
159 if ( nLastInd < nBeginInd )
160 return sal_False;
161
162 nEndInd = nLastInd;
163 }
164
165 return sal_True;
166 }
167
168 return sal_False;
169 }
170
171 // XInitialization
172 // ----------------------------------------------------------------
initialize(const uno::Sequence<uno::Any> & aArguments)173 void SAL_CALL OZipFileAccess::initialize( const uno::Sequence< uno::Any >& aArguments )
174 {
175 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
176
177 if ( m_bDisposed )
178 throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
179
180 if ( m_pZipFile )
181 throw uno::Exception( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // initialization is allowed only one time
182
183 if ( !aArguments.getLength() )
184 throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 );
185
186 OSL_ENSURE( aArguments.getLength() == 1, "Too meny arguments are provided, only the first one will be used!\n" );
187
188 ::rtl::OUString aParamURL;
189 uno::Reference< io::XStream > xStream;
190 uno::Reference< io::XSeekable > xSeekable;
191
192 if ( ( aArguments[0] >>= aParamURL ) )
193 {
194 ::ucbhelper::Content aContent ( aParamURL, uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() );
195 uno::Reference < io::XActiveDataSink > xSink = new ZipPackageSink;
196 if ( aContent.openStream ( xSink ) )
197 {
198 m_xContentStream = xSink->getInputStream();
199 xSeekable = uno::Reference< io::XSeekable >( m_xContentStream, uno::UNO_QUERY );
200 }
201 }
202 else if ( (aArguments[0] >>= xStream ) )
203 {
204 // a writable stream can implement both XStream & XInputStream
205 m_xContentStream = xStream->getInputStream();
206 xSeekable = uno::Reference< io::XSeekable >( xStream, uno::UNO_QUERY );
207 }
208 else if ( !( aArguments[0] >>= m_xContentStream ) )
209 {
210 xSeekable = uno::Reference< io::XSeekable >( m_xContentStream, uno::UNO_QUERY );
211 }
212 else
213 throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 );
214
215 if ( !m_xContentStream.is() )
216 throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
217
218 if ( !xSeekable.is() )
219 {
220 // TODO: after fwkbugfix02 is integrated a helper class can be used to make the stream seekable
221 throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
222 }
223
224 // TODO: in case xSeekable is implemented on separated XStream implementation a wrapper is required
225 m_pZipFile = new ZipFile(
226 m_xContentStream,
227 m_xFactory,
228 sal_True );
229 }
230
231 // XNameAccess
232 // ----------------------------------------------------------------
getByName(const::rtl::OUString & aName)233 uno::Any SAL_CALL OZipFileAccess::getByName( const ::rtl::OUString& aName )
234 {
235 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
236
237 if ( m_bDisposed )
238 throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
239
240 if ( !m_pZipFile )
241 throw io::NotConnectedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
242
243 EntryHash::iterator aIter = m_pZipFile->GetEntryHash().find( aName );
244 if ( aIter == m_pZipFile->GetEntryHash().end() )
245 throw container::NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
246
247 uno::Reference< io::XInputStream > xEntryStream( m_pZipFile->getDataStream( (*aIter).second,
248 ::rtl::Reference< EncryptionData >(),
249 sal_False,
250 m_aMutexHolder ) );
251
252 if ( !xEntryStream.is() )
253 throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
254
255 return uno::makeAny ( xEntryStream );
256 }
257
258 // ----------------------------------------------------------------
getElementNames()259 uno::Sequence< ::rtl::OUString > SAL_CALL OZipFileAccess::getElementNames()
260 {
261 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
262
263 if ( m_bDisposed )
264 throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
265
266 if ( !m_pZipFile )
267 throw io::NotConnectedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
268
269 uno::Sequence< ::rtl::OUString > aNames( m_pZipFile->GetEntryHash().size() );
270 sal_Int32 nLen = 0;
271
272 for ( EntryHash::iterator aIter = m_pZipFile->GetEntryHash().begin(); aIter != m_pZipFile->GetEntryHash().end(); aIter++ )
273 {
274 if ( aNames.getLength() < ++nLen )
275 {
276 OSL_ENSURE( sal_False, "The size must be the same!\n" );
277 aNames.realloc( nLen );
278 }
279
280 aNames[nLen-1] = (*aIter).second.sPath;
281 }
282
283 if ( aNames.getLength() != nLen )
284 {
285 OSL_ENSURE( sal_False, "The size must be the same!\n" );
286 aNames.realloc( nLen );
287 }
288
289 return aNames;
290 }
291
292 // ----------------------------------------------------------------
hasByName(const::rtl::OUString & aName)293 sal_Bool SAL_CALL OZipFileAccess::hasByName( const ::rtl::OUString& aName )
294 {
295 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
296
297 if ( m_bDisposed )
298 throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
299
300 if ( !m_pZipFile )
301 throw io::NotConnectedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
302
303 EntryHash::iterator aIter = m_pZipFile->GetEntryHash().find( aName );
304
305 return ( aIter != m_pZipFile->GetEntryHash().end() );
306 }
307
308 // ----------------------------------------------------------------
getElementType()309 uno::Type SAL_CALL OZipFileAccess::getElementType()
310 {
311 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
312
313 if ( m_bDisposed )
314 throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
315
316 if ( !m_pZipFile )
317 throw io::NotConnectedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
318
319 return getCppuType( ( const uno::Reference< io::XInputStream >* )NULL );
320 }
321
322 // ----------------------------------------------------------------
hasElements()323 sal_Bool SAL_CALL OZipFileAccess::hasElements()
324 {
325 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
326
327 if ( m_bDisposed )
328 throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
329
330 if ( !m_pZipFile )
331 throw io::NotConnectedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
332
333 return ( m_pZipFile->GetEntryHash().size() != 0 );
334 }
335
336 // XZipFileAccess
337 // ----------------------------------------------------------------
getStreamByPattern(const::rtl::OUString & aPatternString)338 uno::Reference< io::XInputStream > SAL_CALL OZipFileAccess::getStreamByPattern( const ::rtl::OUString& aPatternString )
339 {
340 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
341
342 if ( m_bDisposed )
343 throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
344
345 if ( !m_pZipFile )
346 throw io::NotConnectedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
347
348 // Code to compare strings by patterns
349 uno::Sequence< ::rtl::OUString > aPattern = GetPatternsFromString_Impl( aPatternString );
350
351 for ( EntryHash::iterator aIter = m_pZipFile->GetEntryHash().begin(); aIter != m_pZipFile->GetEntryHash().end(); aIter++ )
352 {
353 if ( StringGoodForPattern_Impl( (*aIter).second.sPath, aPattern ) )
354 {
355 uno::Reference< io::XInputStream > xEntryStream( m_pZipFile->getDataStream( (*aIter).second,
356 ::rtl::Reference< EncryptionData >(),
357 sal_False,
358 m_aMutexHolder ) );
359
360 if ( !xEntryStream.is() )
361 throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
362 return xEntryStream;
363 }
364 }
365
366 throw container::NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
367 }
368
369 // XComponent
370 // ----------------------------------------------------------------
dispose()371 void SAL_CALL OZipFileAccess::dispose()
372 {
373 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
374
375 if ( m_bDisposed )
376 throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
377
378 if ( m_pListenersContainer )
379 {
380 lang::EventObject aSource( static_cast< ::cppu::OWeakObject* >(this) );
381 m_pListenersContainer->disposeAndClear( aSource );
382 delete m_pListenersContainer;
383 m_pListenersContainer = NULL;
384 }
385
386 if ( m_pZipFile )
387 {
388 delete m_pZipFile;
389 m_pZipFile = NULL;
390 }
391
392 if ( m_xContentStream.is() )
393 try {
394 m_xContentStream->closeInput();
395 } catch( uno::Exception& )
396 {}
397
398 m_bDisposed = sal_True;
399 }
400
401 // ----------------------------------------------------------------
addEventListener(const uno::Reference<lang::XEventListener> & xListener)402 void SAL_CALL OZipFileAccess::addEventListener( const uno::Reference< lang::XEventListener >& xListener )
403 {
404 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
405
406 if ( m_bDisposed )
407 throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
408
409 if ( !m_pListenersContainer )
410 m_pListenersContainer = new ::cppu::OInterfaceContainerHelper( m_aMutexHolder->GetMutex() );
411 m_pListenersContainer->addInterface( xListener );
412 }
413
414 // ----------------------------------------------------------------
removeEventListener(const uno::Reference<lang::XEventListener> & xListener)415 void SAL_CALL OZipFileAccess::removeEventListener( const uno::Reference< lang::XEventListener >& xListener )
416 {
417 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
418
419 if ( m_bDisposed )
420 throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
421
422 if ( m_pListenersContainer )
423 m_pListenersContainer->removeInterface( xListener );
424 }
425
426 //-------------------------------------------------------------------------
impl_staticGetSupportedServiceNames()427 uno::Sequence< ::rtl::OUString > SAL_CALL OZipFileAccess::impl_staticGetSupportedServiceNames()
428 {
429 uno::Sequence< ::rtl::OUString > aRet(2);
430 aRet[0] = ::rtl::OUString::createFromAscii("com.sun.star.packages.zip.ZipFileAccess");
431 aRet[1] = ::rtl::OUString::createFromAscii("com.sun.star.comp.packages.zip.ZipFileAccess");
432 return aRet;
433 }
434
435 //-------------------------------------------------------------------------
impl_staticGetImplementationName()436 ::rtl::OUString SAL_CALL OZipFileAccess::impl_staticGetImplementationName()
437 {
438 return ::rtl::OUString::createFromAscii("com.sun.star.comp.package.zip.ZipFileAccess");
439 }
440
441 //-------------------------------------------------------------------------
impl_staticCreateSelfInstance(const uno::Reference<lang::XMultiServiceFactory> & xServiceManager)442 uno::Reference< uno::XInterface > SAL_CALL OZipFileAccess::impl_staticCreateSelfInstance(
443 const uno::Reference< lang::XMultiServiceFactory >& xServiceManager )
444 {
445 return uno::Reference< uno::XInterface >( *new OZipFileAccess( xServiceManager ) );
446 }
447
448 //-------------------------------------------------------------------------
getImplementationName()449 ::rtl::OUString SAL_CALL OZipFileAccess::getImplementationName()
450 {
451 return impl_staticGetImplementationName();
452 }
453
454 //-------------------------------------------------------------------------
supportsService(const::rtl::OUString & ServiceName)455 sal_Bool SAL_CALL OZipFileAccess::supportsService( const ::rtl::OUString& ServiceName )
456 {
457 uno::Sequence< ::rtl::OUString > aSeq = impl_staticGetSupportedServiceNames();
458
459 for ( sal_Int32 nInd = 0; nInd < aSeq.getLength(); nInd++ )
460 if ( ServiceName.compareTo( aSeq[nInd] ) == 0 )
461 return sal_True;
462
463 return sal_False;
464 }
465
466 //-------------------------------------------------------------------------
getSupportedServiceNames()467 uno::Sequence< ::rtl::OUString > SAL_CALL OZipFileAccess::getSupportedServiceNames()
468 {
469 return impl_staticGetSupportedServiceNames();
470 }
471