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