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 // ---------------------------------------------------------------- 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 // ---------------------------------------------------------------- 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 distruction must be avoided 69 dispose(); 70 } catch( uno::Exception& ) 71 {} 72 } 73 } 74 } 75 76 // ---------------------------------------------------------------- 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 // ---------------------------------------------------------------- 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 // ---------------------------------------------------------------- 173 void SAL_CALL OZipFileAccess::initialize( const uno::Sequence< uno::Any >& aArguments ) 174 throw ( uno::Exception, 175 uno::RuntimeException ) 176 { 177 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); 178 179 if ( m_bDisposed ) 180 throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 181 182 if ( m_pZipFile ) 183 throw uno::Exception( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // initialization is allowed only one time 184 185 if ( !aArguments.getLength() ) 186 throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); 187 188 OSL_ENSURE( aArguments.getLength() == 1, "Too meny arguments are provided, only the first one will be used!\n" ); 189 190 ::rtl::OUString aParamURL; 191 uno::Reference< io::XStream > xStream; 192 uno::Reference< io::XSeekable > xSeekable; 193 194 if ( ( aArguments[0] >>= aParamURL ) ) 195 { 196 ::ucbhelper::Content aContent ( aParamURL, uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() ); 197 uno::Reference < io::XActiveDataSink > xSink = new ZipPackageSink; 198 if ( aContent.openStream ( xSink ) ) 199 { 200 m_xContentStream = xSink->getInputStream(); 201 xSeekable = uno::Reference< io::XSeekable >( m_xContentStream, uno::UNO_QUERY ); 202 } 203 } 204 else if ( (aArguments[0] >>= xStream ) ) 205 { 206 // a writable stream can implement both XStream & XInputStream 207 m_xContentStream = xStream->getInputStream(); 208 xSeekable = uno::Reference< io::XSeekable >( xStream, uno::UNO_QUERY ); 209 } 210 else if ( !( aArguments[0] >>= m_xContentStream ) ) 211 { 212 xSeekable = uno::Reference< io::XSeekable >( m_xContentStream, uno::UNO_QUERY ); 213 } 214 else 215 throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); 216 217 if ( !m_xContentStream.is() ) 218 throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 219 220 if ( !xSeekable.is() ) 221 { 222 // TODO: after fwkbugfix02 is integrated a helper class can be used to make the stream seekable 223 throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 224 } 225 226 // TODO: in case xSeekable is implemented on separated XStream implementation a wrapper is required 227 m_pZipFile = new ZipFile( 228 m_xContentStream, 229 m_xFactory, 230 sal_True ); 231 } 232 233 // XNameAccess 234 // ---------------------------------------------------------------- 235 uno::Any SAL_CALL OZipFileAccess::getByName( const ::rtl::OUString& aName ) 236 throw ( container::NoSuchElementException, 237 lang::WrappedTargetException, 238 uno::RuntimeException ) 239 { 240 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); 241 242 if ( m_bDisposed ) 243 throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 244 245 if ( !m_pZipFile ) 246 throw io::NotConnectedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 247 248 EntryHash::iterator aIter = m_pZipFile->GetEntryHash().find( aName ); 249 if ( aIter == m_pZipFile->GetEntryHash().end() ) 250 throw container::NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 251 252 uno::Reference< io::XInputStream > xEntryStream( m_pZipFile->getDataStream( (*aIter).second, 253 ::rtl::Reference< EncryptionData >(), 254 sal_False, 255 m_aMutexHolder ) ); 256 257 if ( !xEntryStream.is() ) 258 throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 259 260 return uno::makeAny ( xEntryStream ); 261 } 262 263 // ---------------------------------------------------------------- 264 uno::Sequence< ::rtl::OUString > SAL_CALL OZipFileAccess::getElementNames() 265 throw ( uno::RuntimeException ) 266 { 267 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); 268 269 if ( m_bDisposed ) 270 throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 271 272 if ( !m_pZipFile ) 273 throw io::NotConnectedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 274 275 uno::Sequence< ::rtl::OUString > aNames( m_pZipFile->GetEntryHash().size() ); 276 sal_Int32 nLen = 0; 277 278 for ( EntryHash::iterator aIter = m_pZipFile->GetEntryHash().begin(); aIter != m_pZipFile->GetEntryHash().end(); aIter++ ) 279 { 280 if ( aNames.getLength() < ++nLen ) 281 { 282 OSL_ENSURE( sal_False, "The size must be the same!\n" ); 283 aNames.realloc( nLen ); 284 } 285 286 aNames[nLen-1] = (*aIter).second.sPath; 287 } 288 289 if ( aNames.getLength() != nLen ) 290 { 291 OSL_ENSURE( sal_False, "The size must be the same!\n" ); 292 aNames.realloc( nLen ); 293 } 294 295 return aNames; 296 } 297 298 // ---------------------------------------------------------------- 299 sal_Bool SAL_CALL OZipFileAccess::hasByName( const ::rtl::OUString& aName ) 300 throw (uno::RuntimeException) 301 { 302 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); 303 304 if ( m_bDisposed ) 305 throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 306 307 if ( !m_pZipFile ) 308 throw io::NotConnectedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 309 310 EntryHash::iterator aIter = m_pZipFile->GetEntryHash().find( aName ); 311 312 return ( aIter != m_pZipFile->GetEntryHash().end() ); 313 } 314 315 // ---------------------------------------------------------------- 316 uno::Type SAL_CALL OZipFileAccess::getElementType() 317 throw ( uno::RuntimeException ) 318 { 319 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); 320 321 if ( m_bDisposed ) 322 throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 323 324 if ( !m_pZipFile ) 325 throw io::NotConnectedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 326 327 return getCppuType( ( const uno::Reference< io::XInputStream >* )NULL ); 328 } 329 330 // ---------------------------------------------------------------- 331 sal_Bool SAL_CALL OZipFileAccess::hasElements() 332 throw ( uno::RuntimeException ) 333 { 334 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); 335 336 if ( m_bDisposed ) 337 throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 338 339 if ( !m_pZipFile ) 340 throw io::NotConnectedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 341 342 return ( m_pZipFile->GetEntryHash().size() != 0 ); 343 } 344 345 // XZipFileAccess 346 // ---------------------------------------------------------------- 347 uno::Reference< io::XInputStream > SAL_CALL OZipFileAccess::getStreamByPattern( const ::rtl::OUString& aPatternString ) 348 throw ( container::NoSuchElementException, 349 io::IOException, 350 uno::RuntimeException ) 351 { 352 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); 353 354 if ( m_bDisposed ) 355 throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 356 357 if ( !m_pZipFile ) 358 throw io::NotConnectedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 359 360 // Code to compare strings by patterns 361 uno::Sequence< ::rtl::OUString > aPattern = GetPatternsFromString_Impl( aPatternString ); 362 363 for ( EntryHash::iterator aIter = m_pZipFile->GetEntryHash().begin(); aIter != m_pZipFile->GetEntryHash().end(); aIter++ ) 364 { 365 if ( StringGoodForPattern_Impl( (*aIter).second.sPath, aPattern ) ) 366 { 367 uno::Reference< io::XInputStream > xEntryStream( m_pZipFile->getDataStream( (*aIter).second, 368 ::rtl::Reference< EncryptionData >(), 369 sal_False, 370 m_aMutexHolder ) ); 371 372 if ( !xEntryStream.is() ) 373 throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 374 return xEntryStream; 375 } 376 } 377 378 throw container::NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 379 } 380 381 // XComponent 382 // ---------------------------------------------------------------- 383 void SAL_CALL OZipFileAccess::dispose() 384 throw ( uno::RuntimeException ) 385 { 386 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); 387 388 if ( m_bDisposed ) 389 throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 390 391 if ( m_pListenersContainer ) 392 { 393 lang::EventObject aSource( static_cast< ::cppu::OWeakObject* >(this) ); 394 m_pListenersContainer->disposeAndClear( aSource ); 395 delete m_pListenersContainer; 396 m_pListenersContainer = NULL; 397 } 398 399 if ( m_pZipFile ) 400 { 401 delete m_pZipFile; 402 m_pZipFile = NULL; 403 } 404 405 if ( m_xContentStream.is() ) 406 try { 407 m_xContentStream->closeInput(); 408 } catch( uno::Exception& ) 409 {} 410 411 m_bDisposed = sal_True; 412 } 413 414 // ---------------------------------------------------------------- 415 void SAL_CALL OZipFileAccess::addEventListener( const uno::Reference< lang::XEventListener >& xListener ) 416 throw ( uno::RuntimeException ) 417 { 418 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); 419 420 if ( m_bDisposed ) 421 throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 422 423 if ( !m_pListenersContainer ) 424 m_pListenersContainer = new ::cppu::OInterfaceContainerHelper( m_aMutexHolder->GetMutex() ); 425 m_pListenersContainer->addInterface( xListener ); 426 } 427 428 // ---------------------------------------------------------------- 429 void SAL_CALL OZipFileAccess::removeEventListener( const uno::Reference< lang::XEventListener >& xListener ) 430 throw ( uno::RuntimeException ) 431 { 432 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); 433 434 if ( m_bDisposed ) 435 throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); 436 437 if ( m_pListenersContainer ) 438 m_pListenersContainer->removeInterface( xListener ); 439 } 440 441 //------------------------------------------------------------------------- 442 uno::Sequence< ::rtl::OUString > SAL_CALL OZipFileAccess::impl_staticGetSupportedServiceNames() 443 { 444 uno::Sequence< ::rtl::OUString > aRet(2); 445 aRet[0] = ::rtl::OUString::createFromAscii("com.sun.star.packages.zip.ZipFileAccess"); 446 aRet[1] = ::rtl::OUString::createFromAscii("com.sun.star.comp.packages.zip.ZipFileAccess"); 447 return aRet; 448 } 449 450 //------------------------------------------------------------------------- 451 ::rtl::OUString SAL_CALL OZipFileAccess::impl_staticGetImplementationName() 452 { 453 return ::rtl::OUString::createFromAscii("com.sun.star.comp.package.zip.ZipFileAccess"); 454 } 455 456 //------------------------------------------------------------------------- 457 uno::Reference< uno::XInterface > SAL_CALL OZipFileAccess::impl_staticCreateSelfInstance( 458 const uno::Reference< lang::XMultiServiceFactory >& xServiceManager ) 459 { 460 return uno::Reference< uno::XInterface >( *new OZipFileAccess( xServiceManager ) ); 461 } 462 463 //------------------------------------------------------------------------- 464 ::rtl::OUString SAL_CALL OZipFileAccess::getImplementationName() 465 throw ( uno::RuntimeException ) 466 { 467 return impl_staticGetImplementationName(); 468 } 469 470 //------------------------------------------------------------------------- 471 sal_Bool SAL_CALL OZipFileAccess::supportsService( const ::rtl::OUString& ServiceName ) 472 throw ( uno::RuntimeException ) 473 { 474 uno::Sequence< ::rtl::OUString > aSeq = impl_staticGetSupportedServiceNames(); 475 476 for ( sal_Int32 nInd = 0; nInd < aSeq.getLength(); nInd++ ) 477 if ( ServiceName.compareTo( aSeq[nInd] ) == 0 ) 478 return sal_True; 479 480 return sal_False; 481 } 482 483 //------------------------------------------------------------------------- 484 uno::Sequence< ::rtl::OUString > SAL_CALL OZipFileAccess::getSupportedServiceNames() 485 throw ( uno::RuntimeException ) 486 { 487 return impl_staticGetSupportedServiceNames(); 488 } 489 490