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_scripting.hxx" 26 #include "stringresource.hxx" 27 #include <com/sun/star/io/XTextInputStream.hpp> 28 #include <com/sun/star/io/XTextOutputStream.hpp> 29 #include <com/sun/star/io/XActiveDataSink.hpp> 30 #include <com/sun/star/io/XActiveDataSource.hpp> 31 #include <com/sun/star/io/XStream.hpp> 32 #include <com/sun/star/io/XSeekable.hpp> 33 #include <com/sun/star/embed/ElementModes.hpp> 34 #include <com/sun/star/lang/XMultiComponentFactory.hpp> 35 #ifndef _CPPUHELPER_IMPLEMENTATIONENTRY_HXX_ 36 #include <cppuhelper/implementationentry.hxx> 37 #endif 38 #include <com/sun/star/beans/XPropertySet.hpp> 39 #include <com/sun/star/container/XNameAccess.hpp> 40 41 42 #include <rtl/ustrbuf.hxx> 43 #include <rtl/strbuf.hxx> 44 #include <tools/urlobj.hxx> 45 46 using namespace ::com::sun::star; 47 using namespace ::com::sun::star::lang; 48 using namespace ::com::sun::star::uno; 49 using namespace ::com::sun::star::ucb; 50 using namespace ::com::sun::star::util; 51 using namespace ::com::sun::star::embed; 52 using namespace ::com::sun::star::container; 53 54 55 //......................................................................... 56 namespace stringresource 57 { 58 //......................................................................... 59 60 // ============================================================================= 61 // mutex 62 // ============================================================================= 63 64 ::osl::Mutex& getMutex() 65 { 66 static ::osl::Mutex* s_pMutex = 0; 67 if ( !s_pMutex ) 68 { 69 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); 70 if ( !s_pMutex ) 71 { 72 static ::osl::Mutex s_aMutex; 73 s_pMutex = &s_aMutex; 74 } 75 } 76 return *s_pMutex; 77 } 78 79 80 // ============================================================================= 81 // StringResourceImpl 82 // ============================================================================= 83 84 // component operations 85 static Sequence< ::rtl::OUString > getSupportedServiceNames_StringResourceImpl() 86 { 87 Sequence< ::rtl::OUString > names(1); 88 names[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.resource.StringResource") ); 89 return names; 90 } 91 92 static ::rtl::OUString getImplementationName_StringResourceImpl() 93 { 94 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.scripting.StringResource") ); 95 } 96 97 static Reference< XInterface > SAL_CALL create_StringResourceImpl( 98 Reference< XComponentContext > const & xContext ) 99 SAL_THROW( () ) 100 { 101 return static_cast< ::cppu::OWeakObject * >( new StringResourcePersistenceImpl( xContext ) ); 102 } 103 104 105 // ============================================================================= 106 107 StringResourceImpl::StringResourceImpl( const Reference< XComponentContext >& rxContext ) 108 : m_xContext( rxContext ) 109 , m_pCurrentLocaleItem( NULL ) 110 , m_pDefaultLocaleItem( NULL ) 111 , m_bDefaultModified( false ) 112 , m_aListenerContainer( getMutex() ) 113 , m_bModified( false ) 114 , m_bReadOnly( false ) 115 , m_nNextUniqueNumericId( UNIQUE_NUMBER_NEEDS_INITIALISATION ) 116 { 117 } 118 119 // ============================================================================= 120 121 StringResourceImpl::~StringResourceImpl() 122 { 123 for( LocaleItemVectorIt it = m_aLocaleItemVector.begin(); it != m_aLocaleItemVector.end(); it++ ) 124 { 125 LocaleItem* pLocaleItem = *it; 126 delete pLocaleItem; 127 } 128 129 for( LocaleItemVectorIt it = m_aDeletedLocaleItemVector.begin(); it != m_aDeletedLocaleItemVector.end(); it++ ) 130 { 131 LocaleItem* pLocaleItem = *it; 132 delete pLocaleItem; 133 } 134 } 135 136 137 // ============================================================================= 138 // XServiceInfo 139 140 ::rtl::OUString StringResourceImpl::getImplementationName( ) 141 { 142 return getImplementationName_StringResourceImpl(); 143 } 144 145 sal_Bool StringResourceImpl::supportsService( const ::rtl::OUString& rServiceName ) 146 { 147 Sequence< ::rtl::OUString > aNames( getSupportedServiceNames() ); 148 const ::rtl::OUString* pNames = aNames.getConstArray(); 149 const ::rtl::OUString* pEnd = pNames + aNames.getLength(); 150 for ( ; pNames != pEnd && !pNames->equals( rServiceName ); ++pNames ) 151 ; 152 153 return pNames != pEnd; 154 } 155 156 Sequence< ::rtl::OUString > StringResourceImpl::getSupportedServiceNames( ) 157 { 158 return getSupportedServiceNames_StringResourceImpl(); 159 } 160 161 162 // ============================================================================= 163 // XModifyBroadcaster 164 165 void StringResourceImpl::addModifyListener( const Reference< XModifyListener >& aListener ) 166 { 167 if( !aListener.is() ) 168 throw RuntimeException(); 169 170 ::osl::MutexGuard aGuard( getMutex() ); 171 Reference< XInterface > xIface( aListener, UNO_QUERY ); 172 m_aListenerContainer.addInterface( xIface ); 173 } 174 175 void StringResourceImpl::removeModifyListener( const Reference< XModifyListener >& aListener ) 176 { 177 if( !aListener.is() ) 178 throw RuntimeException(); 179 180 ::osl::MutexGuard aGuard( getMutex() ); 181 Reference< XInterface > xIface( aListener, UNO_QUERY ); 182 m_aListenerContainer.removeInterface( xIface ); 183 } 184 185 186 // ============================================================================= 187 // XStringResourceResolver 188 189 ::rtl::OUString StringResourceImpl::implResolveString 190 ( const ::rtl::OUString& ResourceID, LocaleItem* pLocaleItem ) 191 { 192 ::rtl::OUString aRetStr; 193 bool bSuccess = false; 194 if( pLocaleItem != NULL && loadLocale( pLocaleItem ) ) 195 { 196 IdToStringMap::iterator it = pLocaleItem->m_aIdToStringMap.find( ResourceID ); 197 if( !( it == pLocaleItem->m_aIdToStringMap.end() ) ) 198 { 199 aRetStr = (*it).second; 200 bSuccess = true; 201 } 202 } 203 if( !bSuccess ) 204 { 205 ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "StringResourceImpl: No entry for ResourceID: " ); 206 errorMsg.concat( ResourceID ); 207 throw ::com::sun::star::resource::MissingResourceException( errorMsg, Reference< XInterface >() ); 208 } 209 return aRetStr; 210 } 211 212 ::rtl::OUString StringResourceImpl::resolveString( const ::rtl::OUString& ResourceID ) 213 { 214 ::osl::MutexGuard aGuard( getMutex() ); 215 return implResolveString( ResourceID, m_pCurrentLocaleItem ); 216 } 217 218 ::rtl::OUString StringResourceImpl::resolveStringForLocale( const ::rtl::OUString& ResourceID, const Locale& locale ) 219 { 220 ::osl::MutexGuard aGuard( getMutex() ); 221 LocaleItem* pLocaleItem = getItemForLocale( locale, false ); 222 return implResolveString( ResourceID, pLocaleItem ); 223 } 224 225 sal_Bool StringResourceImpl::implHasEntryForId( const ::rtl::OUString& ResourceID, LocaleItem* pLocaleItem ) 226 { 227 bool bSuccess = false; 228 if( pLocaleItem != NULL && loadLocale( pLocaleItem ) ) 229 { 230 IdToStringMap::iterator it = pLocaleItem->m_aIdToStringMap.find( ResourceID ); 231 if( !( it == pLocaleItem->m_aIdToStringMap.end() ) ) 232 bSuccess = true; 233 } 234 return bSuccess; 235 } 236 237 sal_Bool StringResourceImpl::hasEntryForId( const ::rtl::OUString& ResourceID ) 238 { 239 ::osl::MutexGuard aGuard( getMutex() ); 240 return implHasEntryForId( ResourceID, m_pCurrentLocaleItem ); 241 } 242 243 sal_Bool StringResourceImpl::hasEntryForIdAndLocale( const ::rtl::OUString& ResourceID, 244 const Locale& locale ) 245 { 246 ::osl::MutexGuard aGuard( getMutex() ); 247 LocaleItem* pLocaleItem = getItemForLocale( locale, false ); 248 return implHasEntryForId( ResourceID, pLocaleItem ); 249 } 250 251 Sequence< ::rtl::OUString > StringResourceImpl::implGetResourceIDs( LocaleItem* pLocaleItem ) 252 { 253 Sequence< ::rtl::OUString > aIDSeq( 0 ); 254 if( pLocaleItem && loadLocale( pLocaleItem ) ) 255 { 256 const IdToStringMap& rHashMap = pLocaleItem->m_aIdToStringMap; 257 sal_Int32 nResourceIDCount = rHashMap.size(); 258 aIDSeq.realloc( nResourceIDCount ); 259 ::rtl::OUString* pStrings = aIDSeq.getArray(); 260 261 IdToStringMap::const_iterator it; 262 int iTarget = 0; 263 for( it = rHashMap.begin(); it != rHashMap.end(); it++ ) 264 { 265 ::rtl::OUString aStr = (*it).first; 266 pStrings[iTarget] = aStr; 267 iTarget++; 268 } 269 } 270 return aIDSeq; 271 } 272 273 Sequence< ::rtl::OUString > StringResourceImpl::getResourceIDsForLocale 274 ( const Locale& locale ) 275 { 276 ::osl::MutexGuard aGuard( getMutex() ); 277 LocaleItem* pLocaleItem = getItemForLocale( locale, false ); 278 return implGetResourceIDs( pLocaleItem ); 279 } 280 281 Sequence< ::rtl::OUString > StringResourceImpl::getResourceIDs( ) 282 { 283 ::osl::MutexGuard aGuard( getMutex() ); 284 return implGetResourceIDs( m_pCurrentLocaleItem ); 285 } 286 287 Locale StringResourceImpl::getCurrentLocale() 288 { 289 ::osl::MutexGuard aGuard( getMutex() ); 290 291 Locale aRetLocale; 292 if( m_pCurrentLocaleItem != NULL ) 293 aRetLocale = m_pCurrentLocaleItem->m_locale; 294 return aRetLocale; 295 } 296 297 Locale StringResourceImpl::getDefaultLocale( ) 298 { 299 ::osl::MutexGuard aGuard( getMutex() ); 300 301 Locale aRetLocale; 302 if( m_pDefaultLocaleItem != NULL ) 303 aRetLocale = m_pDefaultLocaleItem->m_locale; 304 return aRetLocale; 305 } 306 307 Sequence< Locale > StringResourceImpl::getLocales( ) 308 { 309 ::osl::MutexGuard aGuard( getMutex() ); 310 311 sal_Int32 nSize = m_aLocaleItemVector.size(); 312 Sequence< Locale > aLocalSeq( nSize ); 313 Locale* pLocales = aLocalSeq.getArray(); 314 int iTarget = 0; 315 for( LocaleItemVectorConstIt it = m_aLocaleItemVector.begin(); it != m_aLocaleItemVector.end(); it++ ) 316 { 317 LocaleItem* pLocaleItem = *it; 318 pLocales[iTarget] = pLocaleItem->m_locale; 319 iTarget++; 320 } 321 return aLocalSeq; 322 } 323 324 325 // ============================================================================= 326 // XStringResourceManager 327 328 void StringResourceImpl::implCheckReadOnly( const sal_Char* pExceptionMsg ) 329 { 330 if( m_bReadOnly ) 331 { 332 ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( pExceptionMsg ); 333 throw NoSupportException( errorMsg, Reference< XInterface >() ); 334 } 335 } 336 337 sal_Bool StringResourceImpl::isReadOnly() 338 { 339 return m_bReadOnly; 340 } 341 342 void StringResourceImpl::implSetCurrentLocale( const Locale& locale, 343 sal_Bool FindClosestMatch, sal_Bool bUseDefaultIfNoMatch ) 344 { 345 ::osl::MutexGuard aGuard( getMutex() ); 346 347 LocaleItem* pLocaleItem = NULL; 348 if( FindClosestMatch ) 349 pLocaleItem = getClosestMatchItemForLocale( locale ); 350 else 351 pLocaleItem = getItemForLocale( locale, true ); 352 353 if( pLocaleItem == NULL && bUseDefaultIfNoMatch ) 354 pLocaleItem = m_pDefaultLocaleItem; 355 356 if( pLocaleItem != NULL ) 357 { 358 loadLocale( pLocaleItem ); 359 m_pCurrentLocaleItem = pLocaleItem; 360 361 // Only notify without modifying 362 implNotifyListeners(); 363 } 364 } 365 366 void StringResourceImpl::setCurrentLocale( const Locale& locale, sal_Bool FindClosestMatch ) 367 { 368 sal_Bool bUseDefaultIfNoMatch = false; 369 implSetCurrentLocale( locale, FindClosestMatch, bUseDefaultIfNoMatch ); 370 } 371 372 void StringResourceImpl::setDefaultLocale( const Locale& locale ) 373 { 374 ::osl::MutexGuard aGuard( getMutex() ); 375 implCheckReadOnly( "StringResourceImpl::setDefaultLocale(): Read only" ); 376 377 LocaleItem* pLocaleItem = getItemForLocale( locale, true ); 378 if( pLocaleItem && pLocaleItem != m_pDefaultLocaleItem ) 379 { 380 if( m_pDefaultLocaleItem ) 381 { 382 LocaleItem* pChangedDefaultLocaleItem = new LocaleItem( m_pDefaultLocaleItem->m_locale ); 383 m_aChangedDefaultLocaleVector.push_back( pChangedDefaultLocaleItem ); 384 } 385 386 m_pDefaultLocaleItem = pLocaleItem; 387 m_bDefaultModified = true; 388 implModified(); 389 } 390 } 391 392 void StringResourceImpl::implSetString( const ::rtl::OUString& ResourceID, 393 const ::rtl::OUString& Str, LocaleItem* pLocaleItem ) 394 { 395 if( pLocaleItem != NULL && loadLocale( pLocaleItem ) ) 396 { 397 IdToStringMap& rHashMap = pLocaleItem->m_aIdToStringMap; 398 399 IdToStringMap::iterator it = rHashMap.find( ResourceID ); 400 bool bNew = ( it == rHashMap.end() ); 401 if( bNew ) 402 { 403 IdToIndexMap& rIndexMap = pLocaleItem->m_aIdToIndexMap; 404 rIndexMap[ ResourceID ] = pLocaleItem->m_nNextIndex++; 405 implScanIdForNumber( ResourceID ); 406 } 407 rHashMap[ ResourceID ] = Str; 408 pLocaleItem->m_bModified = true; 409 implModified(); 410 } 411 } 412 413 void StringResourceImpl::setString( const ::rtl::OUString& ResourceID, const ::rtl::OUString& Str ) 414 { 415 ::osl::MutexGuard aGuard( getMutex() ); 416 implCheckReadOnly( "StringResourceImpl::setString(): Read only" ); 417 implSetString( ResourceID, Str, m_pCurrentLocaleItem ); 418 } 419 420 void StringResourceImpl::setStringForLocale 421 ( const ::rtl::OUString& ResourceID, const ::rtl::OUString& Str, const Locale& locale ) 422 { 423 ::osl::MutexGuard aGuard( getMutex() ); 424 implCheckReadOnly( "StringResourceImpl::setStringForLocale(): Read only" ); 425 LocaleItem* pLocaleItem = getItemForLocale( locale, false ); 426 implSetString( ResourceID, Str, pLocaleItem ); 427 } 428 429 void StringResourceImpl::implRemoveId( const ::rtl::OUString& ResourceID, LocaleItem* pLocaleItem ) 430 { 431 if( pLocaleItem != NULL && loadLocale( pLocaleItem ) ) 432 { 433 IdToStringMap& rHashMap = pLocaleItem->m_aIdToStringMap; 434 IdToStringMap::iterator it = rHashMap.find( ResourceID ); 435 if( it == rHashMap.end() ) 436 { 437 ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "StringResourceImpl: No entries for ResourceID: " ); 438 errorMsg.concat( ResourceID ); 439 throw ::com::sun::star::resource::MissingResourceException( errorMsg, Reference< XInterface >() ); 440 } 441 rHashMap.erase( it ); 442 pLocaleItem->m_bModified = true; 443 implModified(); 444 } 445 } 446 447 void StringResourceImpl::removeId( const ::rtl::OUString& ResourceID ) 448 { 449 ::osl::MutexGuard aGuard( getMutex() ); 450 implCheckReadOnly( "StringResourceImpl::removeId(): Read only" ); 451 implRemoveId( ResourceID, m_pCurrentLocaleItem ); 452 } 453 454 void StringResourceImpl::removeIdForLocale( const ::rtl::OUString& ResourceID, const Locale& locale ) 455 { 456 ::osl::MutexGuard aGuard( getMutex() ); 457 implCheckReadOnly( "StringResourceImpl::removeIdForLocale(): Read only" ); 458 LocaleItem* pLocaleItem = getItemForLocale( locale, false ); 459 implRemoveId( ResourceID, pLocaleItem ); 460 } 461 462 void StringResourceImpl::newLocale( const Locale& locale ) 463 { 464 ::osl::MutexGuard aGuard( getMutex() ); 465 implCheckReadOnly( "StringResourceImpl::newLocale(): Read only" ); 466 467 if( getItemForLocale( locale, false ) != NULL ) 468 { 469 ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "StringResourceImpl: locale already exists" ); 470 throw ElementExistException( errorMsg, Reference< XInterface >() ); 471 } 472 473 // TODO?: Check if locale is valid? How? 474 bool bValid = true; 475 if( bValid ) 476 { 477 LocaleItem* pLocaleItem = new LocaleItem( locale ); 478 m_aLocaleItemVector.push_back( pLocaleItem ); 479 pLocaleItem->m_bModified = true; 480 481 // Copy strings from default locale 482 LocaleItem* pCopyFromItem = m_pDefaultLocaleItem; 483 if( pCopyFromItem == NULL ) 484 pCopyFromItem = m_pCurrentLocaleItem; 485 if( pCopyFromItem != NULL && loadLocale( pCopyFromItem ) ) 486 { 487 const IdToStringMap& rSourceMap = pCopyFromItem->m_aIdToStringMap; 488 IdToStringMap& rTargetMap = pLocaleItem->m_aIdToStringMap; 489 IdToStringMap::const_iterator it; 490 for( it = rSourceMap.begin(); it != rSourceMap.end(); it++ ) 491 { 492 ::rtl::OUString aId = (*it).first; 493 ::rtl::OUString aStr = (*it).second; 494 rTargetMap[ aId ] = aStr; 495 } 496 497 const IdToIndexMap& rSourceIndexMap = pCopyFromItem->m_aIdToIndexMap; 498 IdToIndexMap& rTargetIndexMap = pLocaleItem->m_aIdToIndexMap; 499 IdToIndexMap::const_iterator it_index; 500 for( it_index = rSourceIndexMap.begin(); it_index != rSourceIndexMap.end(); it_index++ ) 501 { 502 ::rtl::OUString aId = (*it_index).first; 503 sal_Int32 nIndex = (*it_index).second; 504 rTargetIndexMap[ aId ] = nIndex; 505 } 506 pLocaleItem->m_nNextIndex = pCopyFromItem->m_nNextIndex; 507 } 508 509 if( m_pCurrentLocaleItem == NULL ) 510 m_pCurrentLocaleItem = pLocaleItem; 511 512 if( m_pDefaultLocaleItem == NULL ) 513 { 514 m_pDefaultLocaleItem = pLocaleItem; 515 m_bDefaultModified = true; 516 } 517 518 implModified(); 519 } 520 else 521 { 522 ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "StringResourceImpl: Invalid locale" ); 523 throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 0 ); 524 } 525 } 526 527 void StringResourceImpl::removeLocale( const Locale& locale ) 528 { 529 ::osl::MutexGuard aGuard( getMutex() ); 530 implCheckReadOnly( "StringResourceImpl::removeLocale(): Read only" ); 531 532 LocaleItem* pRemoveItem = getItemForLocale( locale, true ); 533 if( pRemoveItem ) 534 { 535 // Last locale? 536 sal_Int32 nLocaleCount = m_aLocaleItemVector.size(); 537 if( nLocaleCount > 1 ) 538 { 539 LocaleItem* pFallbackItem = NULL; 540 if( m_pCurrentLocaleItem == pRemoveItem || 541 m_pDefaultLocaleItem == pRemoveItem ) 542 { 543 for( LocaleItemVectorIt it = m_aLocaleItemVector.begin(); it != m_aLocaleItemVector.end(); it++ ) 544 { 545 LocaleItem* pLocaleItem = *it; 546 if( pLocaleItem != pRemoveItem ) 547 { 548 pFallbackItem = pLocaleItem; 549 break; 550 } 551 } 552 if( m_pCurrentLocaleItem == pRemoveItem ) 553 { 554 sal_Bool FindClosestMatch = false; 555 setCurrentLocale( pFallbackItem->m_locale, FindClosestMatch ); 556 } 557 if( m_pDefaultLocaleItem == pRemoveItem ) 558 { 559 setDefaultLocale( pFallbackItem->m_locale ); 560 } 561 } 562 } 563 for( LocaleItemVectorIt it = m_aLocaleItemVector.begin(); it != m_aLocaleItemVector.end(); it++ ) 564 { 565 LocaleItem* pLocaleItem = *it; 566 if( pLocaleItem == pRemoveItem ) 567 { 568 // Remember locale item to delete file while storing 569 m_aDeletedLocaleItemVector.push_back( pLocaleItem ); 570 571 // Last locale? 572 if( nLocaleCount == 1 ) 573 { 574 m_nNextUniqueNumericId = 0; 575 if( m_pDefaultLocaleItem ) 576 { 577 LocaleItem* pChangedDefaultLocaleItem = new LocaleItem( m_pDefaultLocaleItem->m_locale ); 578 m_aChangedDefaultLocaleVector.push_back( pChangedDefaultLocaleItem ); 579 } 580 m_pCurrentLocaleItem = NULL; 581 m_pDefaultLocaleItem = NULL; 582 } 583 584 m_aLocaleItemVector.erase( it ); 585 586 implModified(); 587 break; 588 } 589 } 590 } 591 } 592 593 void StringResourceImpl::implScanIdForNumber( const ::rtl::OUString& ResourceID ) 594 { 595 const sal_Unicode* pSrc = ResourceID.getStr(); 596 sal_Int32 nLen = ResourceID.getLength(); 597 598 sal_Int32 nNumber = 0; 599 for( sal_Int32 i = 0 ; i < nLen ; i++ ) 600 { 601 sal_Unicode c = pSrc[i]; 602 if( c >= '0' && c <= '9' ) 603 { 604 sal_uInt16 nDigitVal = c - '0'; 605 nNumber = 10*nNumber + nDigitVal; 606 } 607 else 608 break; 609 } 610 611 if( m_nNextUniqueNumericId < nNumber + 1 ) 612 m_nNextUniqueNumericId = nNumber + 1; 613 } 614 615 sal_Int32 StringResourceImpl::getUniqueNumericId( ) 616 { 617 if( m_nNextUniqueNumericId == UNIQUE_NUMBER_NEEDS_INITIALISATION ) 618 { 619 implLoadAllLocales(); 620 m_nNextUniqueNumericId = 0; 621 } 622 623 if( m_nNextUniqueNumericId < UNIQUE_NUMBER_NEEDS_INITIALISATION ) 624 { 625 ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "getUniqueNumericId: Extended sal_Int32 range" ); 626 throw NoSupportException( errorMsg, Reference< XInterface >() ); 627 } 628 return m_nNextUniqueNumericId; 629 } 630 631 632 // ============================================================================= 633 // Private helper methods 634 635 LocaleItem* StringResourceImpl::getItemForLocale 636 ( const Locale& locale, sal_Bool bException ) 637 { 638 LocaleItem* pRetItem = NULL; 639 640 // Search for locale 641 for( LocaleItemVectorConstIt it = m_aLocaleItemVector.begin(); it != m_aLocaleItemVector.end(); it++ ) 642 { 643 LocaleItem* pLocaleItem = *it; 644 if( pLocaleItem ) 645 { 646 Locale& cmp_locale = pLocaleItem->m_locale; 647 if( cmp_locale.Language == locale.Language && 648 cmp_locale.Country == locale.Country && 649 cmp_locale.Variant == locale.Variant ) 650 { 651 pRetItem = pLocaleItem; 652 break; 653 } 654 } 655 } 656 657 if( pRetItem == NULL && bException ) 658 { 659 ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "StringResourceImpl: Invalid locale" ); 660 throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 0 ); 661 } 662 return pRetItem; 663 } 664 665 // Returns the LocalItem for a given locale, if it exists, otherwise NULL 666 // This method performs a closest match search, at least the language must match 667 LocaleItem* StringResourceImpl::getClosestMatchItemForLocale( const Locale& locale ) 668 { 669 LocaleItem* pRetItem = NULL; 670 671 // Search for locale 672 for( sal_Int32 iPass = 0 ; iPass <= 2 ; ++iPass ) 673 { 674 for( LocaleItemVectorConstIt it = m_aLocaleItemVector.begin(); it != m_aLocaleItemVector.end(); it++ ) 675 { 676 LocaleItem* pLocaleItem = *it; 677 if( pLocaleItem ) 678 { 679 Locale& cmp_locale = pLocaleItem->m_locale; 680 if( cmp_locale.Language == locale.Language && 681 (iPass > 1 || cmp_locale.Country == locale.Country) && 682 (iPass > 0 || cmp_locale.Variant == locale.Variant) ) 683 { 684 pRetItem = pLocaleItem; 685 break; 686 } 687 } 688 } 689 if( pRetItem ) 690 break; 691 } 692 693 return pRetItem; 694 } 695 696 void StringResourceImpl::implModified( void ) 697 { 698 m_bModified = true; 699 implNotifyListeners(); 700 } 701 702 void StringResourceImpl::implNotifyListeners( void ) 703 { 704 EventObject aEvent; 705 aEvent.Source = static_cast< XInterface* >( (OWeakObject*)this ); 706 707 ::cppu::OInterfaceIteratorHelper it( m_aListenerContainer ); 708 while( it.hasMoreElements() ) 709 { 710 Reference< XInterface > xIface = it.next(); 711 Reference< XModifyListener > xListener( xIface, UNO_QUERY ); 712 try 713 { 714 xListener->modified( aEvent ); 715 } 716 catch(RuntimeException&) 717 { 718 it.remove(); 719 } 720 } 721 } 722 723 724 // ============================================================================= 725 // Loading 726 727 bool StringResourceImpl::loadLocale( LocaleItem* pLocaleItem ) 728 { 729 // Base implementation has nothing to load 730 (void)pLocaleItem; 731 return true; 732 } 733 734 void StringResourceImpl::implLoadAllLocales( void ) 735 { 736 // Base implementation has nothing to load 737 } 738 739 740 Reference< XMultiComponentFactory > StringResourceImpl::getMultiComponentFactory( void ) 741 { 742 ::osl::MutexGuard aGuard( getMutex() ); 743 744 if( !m_xMCF.is() ) 745 { 746 Reference< XMultiComponentFactory > xSMgr( m_xContext->getServiceManager(), UNO_QUERY ); 747 if( !xSMgr.is() ) 748 { 749 throw RuntimeException( 750 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StringResourceImpl::getMultiComponentFactory: Couldn't instantiate MultiComponentFactory" ) ), 751 Reference< XInterface >() ); 752 } 753 m_xMCF = xSMgr; 754 } 755 return m_xMCF; 756 } 757 758 759 // ============================================================================= 760 // StringResourcePersistenceImpl 761 // ============================================================================= 762 763 StringResourcePersistenceImpl::StringResourcePersistenceImpl( const Reference< XComponentContext >& rxContext ) 764 : StringResourcePersistenceImpl_BASE( rxContext ) 765 { 766 } 767 768 // ----------------------------------------------------------------------------- 769 770 StringResourcePersistenceImpl::~StringResourcePersistenceImpl() 771 { 772 } 773 774 // ----------------------------------------------------------------------------- 775 // XServiceInfo 776 // ----------------------------------------------------------------------------- 777 778 ::rtl::OUString StringResourcePersistenceImpl::getImplementationName( ) 779 { 780 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM 781 ( "com.sun.star.comp.scripting.StringResourceWithLocation") ); 782 } 783 784 // ----------------------------------------------------------------------------- 785 786 sal_Bool StringResourcePersistenceImpl::supportsService( const ::rtl::OUString& rServiceName ) 787 { 788 return StringResourceImpl::supportsService( rServiceName ); 789 } 790 791 // ----------------------------------------------------------------------------- 792 793 Sequence< ::rtl::OUString > StringResourcePersistenceImpl::getSupportedServiceNames( ) 794 { 795 return StringResourceImpl::getSupportedServiceNames(); 796 } 797 798 // ----------------------------------------------------------------------------- 799 // XInitialization base functionality for derived classes 800 // ----------------------------------------------------------------------------- 801 802 static ::rtl::OUString aNameBaseDefaultStr = ::rtl::OUString::createFromAscii( "strings" ); 803 804 void StringResourcePersistenceImpl::implInitializeCommonParameters 805 ( const Sequence< Any >& aArguments ) 806 { 807 bool bReadOnlyOk = (aArguments[1] >>= m_bReadOnly); 808 if( !bReadOnlyOk ) 809 { 810 ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "XInitialization::initialize: Expected ReadOnly flag" ); 811 throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 1 ); 812 } 813 814 com::sun::star::lang::Locale aCurrentLocale; 815 bool bLocaleOk = (aArguments[2] >>= aCurrentLocale); 816 if( !bLocaleOk ) 817 { 818 ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "XInitialization::initialize: Expected Locale" ); 819 throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 2 ); 820 } 821 822 bool bNameBaseOk = (aArguments[3] >>= m_aNameBase); 823 if( !bNameBaseOk ) 824 { 825 ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "XInitialization::initialize: Expected NameBase string" ); 826 throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 3 ); 827 } 828 if( m_aNameBase.getLength() == 0 ) 829 m_aNameBase = aNameBaseDefaultStr; 830 831 bool bCommentOk = (aArguments[4] >>= m_aComment); 832 if( !bCommentOk ) 833 { 834 ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "XInitialization::initialize: Expected Comment string" ); 835 throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 4 ); 836 } 837 838 implScanLocales(); 839 840 sal_Bool FindClosestMatch = true; 841 sal_Bool bUseDefaultIfNoMatch = true; 842 implSetCurrentLocale( aCurrentLocale, FindClosestMatch, bUseDefaultIfNoMatch ); 843 } 844 845 // ----------------------------------------------------------------------------- 846 // Forwarding calls to base class 847 848 // XModifyBroadcaster 849 void StringResourcePersistenceImpl::addModifyListener( const Reference< XModifyListener >& aListener ) 850 { 851 StringResourceImpl::addModifyListener( aListener ); 852 } 853 void StringResourcePersistenceImpl::removeModifyListener( const Reference< XModifyListener >& aListener ) 854 { 855 StringResourceImpl::removeModifyListener( aListener ); 856 } 857 858 // XStringResourceResolver 859 ::rtl::OUString StringResourcePersistenceImpl::resolveString( const ::rtl::OUString& ResourceID ) 860 { 861 return StringResourceImpl::resolveString( ResourceID ) ; 862 } 863 ::rtl::OUString StringResourcePersistenceImpl::resolveStringForLocale( const ::rtl::OUString& ResourceID, const Locale& locale ) 864 { 865 return StringResourceImpl::resolveStringForLocale( ResourceID, locale ); 866 } 867 sal_Bool StringResourcePersistenceImpl::hasEntryForId( const ::rtl::OUString& ResourceID ) 868 { 869 return StringResourceImpl::hasEntryForId( ResourceID ) ; 870 } 871 sal_Bool StringResourcePersistenceImpl::hasEntryForIdAndLocale( const ::rtl::OUString& ResourceID, 872 const Locale& locale ) 873 { 874 return StringResourceImpl::hasEntryForIdAndLocale( ResourceID, locale ); 875 } 876 Locale StringResourcePersistenceImpl::getCurrentLocale() 877 { 878 return StringResourceImpl::getCurrentLocale(); 879 } 880 Locale StringResourcePersistenceImpl::getDefaultLocale( ) 881 { 882 return StringResourceImpl::getDefaultLocale(); 883 } 884 Sequence< Locale > StringResourcePersistenceImpl::getLocales( ) 885 { 886 return StringResourceImpl::getLocales(); 887 } 888 889 // XStringResourceManager 890 sal_Bool StringResourcePersistenceImpl::isReadOnly() 891 { 892 return StringResourceImpl::isReadOnly(); 893 } 894 void StringResourcePersistenceImpl::setCurrentLocale( const Locale& locale, sal_Bool FindClosestMatch ) 895 { 896 StringResourceImpl::setCurrentLocale( locale, FindClosestMatch ); 897 } 898 void StringResourcePersistenceImpl::setDefaultLocale( const Locale& locale ) 899 { 900 StringResourceImpl::setDefaultLocale( locale ); 901 } 902 Sequence< ::rtl::OUString > StringResourcePersistenceImpl::getResourceIDs( ) 903 { 904 return StringResourceImpl::getResourceIDs(); 905 } 906 void StringResourcePersistenceImpl::setString( const ::rtl::OUString& ResourceID, const ::rtl::OUString& Str ) 907 { 908 StringResourceImpl::setString( ResourceID, Str ); 909 } 910 void StringResourcePersistenceImpl::setStringForLocale 911 ( const ::rtl::OUString& ResourceID, const ::rtl::OUString& Str, const Locale& locale ) 912 { 913 StringResourceImpl::setStringForLocale( ResourceID, Str, locale ); 914 } 915 Sequence< ::rtl::OUString > StringResourcePersistenceImpl::getResourceIDsForLocale 916 ( const Locale& locale ) 917 { 918 return StringResourceImpl::getResourceIDsForLocale( locale ); 919 } 920 void StringResourcePersistenceImpl::removeId( const ::rtl::OUString& ResourceID ) 921 { 922 StringResourceImpl::removeId( ResourceID ); 923 } 924 void StringResourcePersistenceImpl::removeIdForLocale( const ::rtl::OUString& ResourceID, const Locale& locale ) 925 { 926 StringResourceImpl::removeIdForLocale( ResourceID, locale ); 927 } 928 void StringResourcePersistenceImpl::newLocale( const Locale& locale ) 929 { 930 StringResourceImpl::newLocale( locale ); 931 } 932 void StringResourcePersistenceImpl::removeLocale( const Locale& locale ) 933 { 934 StringResourceImpl::removeLocale( locale ); 935 } 936 sal_Int32 StringResourcePersistenceImpl::getUniqueNumericId( ) 937 { 938 return StringResourceImpl::getUniqueNumericId(); 939 } 940 941 // ----------------------------------------------------------------------------- 942 // XStringResourcePersistence 943 944 void StringResourcePersistenceImpl::store() 945 { 946 } 947 948 sal_Bool StringResourcePersistenceImpl::isModified( ) 949 { 950 ::osl::MutexGuard aGuard( getMutex() ); 951 952 return m_bModified; 953 } 954 955 void StringResourcePersistenceImpl::setComment( const ::rtl::OUString& Comment ) 956 { 957 m_aComment = Comment; 958 } 959 960 void StringResourcePersistenceImpl::storeToStorage( const Reference< XStorage >& Storage, 961 const ::rtl::OUString& NameBase, const ::rtl::OUString& Comment ) 962 { 963 ::osl::MutexGuard aGuard( getMutex() ); 964 965 bool bUsedForStore = false; 966 bool bStoreAll = true; 967 implStoreAtStorage( NameBase, Comment, Storage, bUsedForStore, bStoreAll ); 968 } 969 970 void StringResourcePersistenceImpl::implStoreAtStorage 971 ( 972 const ::rtl::OUString& aNameBase, 973 const ::rtl::OUString& aComment, 974 const Reference< ::com::sun::star::embed::XStorage >& Storage, 975 bool bUsedForStore, 976 bool bStoreAll 977 ) 978 { 979 // Delete files for deleted locales 980 if( bUsedForStore ) 981 { 982 while( m_aDeletedLocaleItemVector.size() > 0 ) 983 { 984 LocaleItemVectorIt it = m_aDeletedLocaleItemVector.begin(); 985 LocaleItem* pLocaleItem = *it; 986 if( pLocaleItem != NULL ) 987 { 988 ::rtl::OUString aStreamName = implGetFileNameForLocaleItem( pLocaleItem, m_aNameBase ); 989 aStreamName += ::rtl::OUString::createFromAscii( ".properties" ); 990 991 try 992 { 993 Storage->removeElement( aStreamName ); 994 } 995 catch( Exception& ) 996 {} 997 998 m_aDeletedLocaleItemVector.erase( it ); 999 delete pLocaleItem; 1000 } 1001 } 1002 } 1003 1004 for( LocaleItemVectorConstIt it = m_aLocaleItemVector.begin(); it != m_aLocaleItemVector.end(); it++ ) 1005 { 1006 LocaleItem* pLocaleItem = *it; 1007 if( pLocaleItem != NULL && (bStoreAll || pLocaleItem->m_bModified) && 1008 loadLocale( pLocaleItem ) ) 1009 { 1010 ::rtl::OUString aStreamName = implGetFileNameForLocaleItem( pLocaleItem, aNameBase ); 1011 aStreamName += ::rtl::OUString::createFromAscii( ".properties" ); 1012 1013 Reference< io::XStream > xElementStream = 1014 Storage->openStreamElement( aStreamName, ElementModes::READWRITE ); 1015 1016 ::rtl::OUString aPropName = ::rtl::OUString::createFromAscii( "MediaType" ); 1017 ::rtl::OUString aMime = ::rtl::OUString::createFromAscii( "text/plain" ); 1018 1019 uno::Reference< beans::XPropertySet > xProps( xElementStream, uno::UNO_QUERY ); 1020 OSL_ENSURE( xProps.is(), "The StorageStream must implement XPropertySet interface!\n" ); 1021 if ( xProps.is() ) 1022 { 1023 xProps->setPropertyValue( aPropName, uno::makeAny( aMime ) ); 1024 1025 aPropName = ::rtl::OUString::createFromAscii( "UseCommonStoragePasswordEncryption" ); 1026 xProps->setPropertyValue( aPropName, uno::makeAny( sal_True ) ); 1027 } 1028 1029 Reference< io::XOutputStream > xOutputStream = xElementStream->getOutputStream(); 1030 if( xOutputStream.is() ) 1031 implWritePropertiesFile( pLocaleItem, xOutputStream, aComment ); 1032 xOutputStream->closeOutput(); 1033 1034 if( bUsedForStore ) 1035 pLocaleItem->m_bModified = false; 1036 } 1037 } 1038 1039 // Delete files for changed defaults 1040 if( bUsedForStore ) 1041 { 1042 for( LocaleItemVectorIt it = m_aChangedDefaultLocaleVector.begin(); 1043 it != m_aChangedDefaultLocaleVector.end(); it++ ) 1044 { 1045 LocaleItem* pLocaleItem = *it; 1046 if( pLocaleItem != NULL ) 1047 { 1048 ::rtl::OUString aStreamName = implGetFileNameForLocaleItem( pLocaleItem, m_aNameBase ); 1049 aStreamName += ::rtl::OUString::createFromAscii( ".default" ); 1050 1051 try 1052 { 1053 Storage->removeElement( aStreamName ); 1054 } 1055 catch( Exception& ) 1056 {} 1057 1058 delete pLocaleItem; 1059 } 1060 } 1061 m_aChangedDefaultLocaleVector.clear(); 1062 } 1063 1064 // Default locale 1065 if( m_pDefaultLocaleItem != NULL && (bStoreAll || m_bDefaultModified) ) 1066 { 1067 ::rtl::OUString aStreamName = implGetFileNameForLocaleItem( m_pDefaultLocaleItem, aNameBase ); 1068 aStreamName += ::rtl::OUString::createFromAscii( ".default" ); 1069 1070 Reference< io::XStream > xElementStream = 1071 Storage->openStreamElement( aStreamName, ElementModes::READWRITE ); 1072 1073 ::rtl::OUString aPropName = ::rtl::OUString::createFromAscii( "MediaType" ); 1074 ::rtl::OUString aMime = ::rtl::OUString::createFromAscii( "text/plain" ); 1075 1076 // Only create stream without content 1077 Reference< io::XOutputStream > xOutputStream = xElementStream->getOutputStream(); 1078 xOutputStream->closeOutput(); 1079 1080 if( bUsedForStore ) 1081 m_bDefaultModified = false; 1082 } 1083 } 1084 1085 void StringResourcePersistenceImpl::storeToURL( const ::rtl::OUString& URL, 1086 const ::rtl::OUString& NameBase, const ::rtl::OUString& Comment, 1087 const Reference< ::com::sun::star::task::XInteractionHandler >& Handler ) 1088 { 1089 ::osl::MutexGuard aGuard( getMutex() ); 1090 1091 bool bUsedForStore = false; 1092 bool bStoreAll = true; 1093 1094 Reference< XMultiComponentFactory > xMCF = getMultiComponentFactory(); 1095 Reference< ucb::XSimpleFileAccess > xFileAccess; 1096 xFileAccess = Reference< ucb::XSimpleFileAccess >( xMCF->createInstanceWithContext 1097 ( ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ), 1098 m_xContext ), UNO_QUERY ); 1099 if( xFileAccess.is() && Handler.is() ) 1100 xFileAccess->setInteractionHandler( Handler ); 1101 1102 implStoreAtLocation( URL, NameBase, Comment, xFileAccess, bUsedForStore, bStoreAll ); 1103 } 1104 1105 void StringResourcePersistenceImpl::implKillRemovedLocaleFiles 1106 ( 1107 const ::rtl::OUString& Location, 1108 const ::rtl::OUString& aNameBase, 1109 const ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XSimpleFileAccess >& xFileAccess 1110 ) 1111 { 1112 // Delete files for deleted locales 1113 while( m_aDeletedLocaleItemVector.size() > 0 ) 1114 { 1115 LocaleItemVectorIt it = m_aDeletedLocaleItemVector.begin(); 1116 LocaleItem* pLocaleItem = *it; 1117 if( pLocaleItem != NULL ) 1118 { 1119 ::rtl::OUString aCompleteFileName = 1120 implGetPathForLocaleItem( pLocaleItem, aNameBase, Location ); 1121 if( xFileAccess->exists( aCompleteFileName ) ) 1122 xFileAccess->kill( aCompleteFileName ); 1123 1124 m_aDeletedLocaleItemVector.erase( it ); 1125 delete pLocaleItem; 1126 } 1127 } 1128 } 1129 1130 void StringResourcePersistenceImpl::implKillChangedDefaultFiles 1131 ( 1132 const ::rtl::OUString& Location, 1133 const ::rtl::OUString& aNameBase, 1134 const ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XSimpleFileAccess >& xFileAccess 1135 ) 1136 { 1137 // Delete files for changed defaults 1138 for( LocaleItemVectorIt it = m_aChangedDefaultLocaleVector.begin(); 1139 it != m_aChangedDefaultLocaleVector.end(); it++ ) 1140 { 1141 LocaleItem* pLocaleItem = *it; 1142 if( pLocaleItem != NULL ) 1143 { 1144 ::rtl::OUString aCompleteFileName = 1145 implGetPathForLocaleItem( pLocaleItem, aNameBase, Location, true ); 1146 if( xFileAccess->exists( aCompleteFileName ) ) 1147 xFileAccess->kill( aCompleteFileName ); 1148 1149 delete pLocaleItem; 1150 } 1151 } 1152 m_aChangedDefaultLocaleVector.clear(); 1153 } 1154 1155 void StringResourcePersistenceImpl::implStoreAtLocation 1156 ( 1157 const ::rtl::OUString& Location, 1158 const ::rtl::OUString& aNameBase, 1159 const ::rtl::OUString& aComment, 1160 const Reference< ucb::XSimpleFileAccess >& xFileAccess, 1161 bool bUsedForStore, 1162 bool bStoreAll, 1163 bool bKillAll 1164 ) 1165 { 1166 // Delete files for deleted locales 1167 if( bUsedForStore || bKillAll ) 1168 implKillRemovedLocaleFiles( Location, aNameBase, xFileAccess ); 1169 1170 for( LocaleItemVectorConstIt it = m_aLocaleItemVector.begin(); it != m_aLocaleItemVector.end(); it++ ) 1171 { 1172 LocaleItem* pLocaleItem = *it; 1173 if( pLocaleItem != NULL && (bStoreAll || bKillAll || pLocaleItem->m_bModified) && 1174 loadLocale( pLocaleItem ) ) 1175 { 1176 ::rtl::OUString aCompleteFileName = 1177 implGetPathForLocaleItem( pLocaleItem, aNameBase, Location ); 1178 if( xFileAccess->exists( aCompleteFileName ) ) 1179 xFileAccess->kill( aCompleteFileName ); 1180 1181 if( !bKillAll ) 1182 { 1183 // Create Output stream 1184 Reference< io::XOutputStream > xOutputStream = xFileAccess->openFileWrite( aCompleteFileName ); 1185 if( xOutputStream.is() ) 1186 { 1187 implWritePropertiesFile( pLocaleItem, xOutputStream, aComment ); 1188 xOutputStream->closeOutput(); 1189 } 1190 if( bUsedForStore ) 1191 pLocaleItem->m_bModified = false; 1192 } 1193 } 1194 } 1195 1196 // Delete files for changed defaults 1197 if( bUsedForStore || bKillAll ) 1198 implKillChangedDefaultFiles( Location, aNameBase, xFileAccess ); 1199 1200 // Default locale 1201 if( m_pDefaultLocaleItem != NULL && (bStoreAll || bKillAll || m_bDefaultModified) ) 1202 { 1203 ::rtl::OUString aCompleteFileName = 1204 implGetPathForLocaleItem( m_pDefaultLocaleItem, aNameBase, Location, true ); 1205 if( xFileAccess->exists( aCompleteFileName ) ) 1206 xFileAccess->kill( aCompleteFileName ); 1207 1208 if( !bKillAll ) 1209 { 1210 // Create Output stream 1211 Reference< io::XOutputStream > xOutputStream = xFileAccess->openFileWrite( aCompleteFileName ); 1212 if( xOutputStream.is() ) 1213 xOutputStream->closeOutput(); 1214 1215 if( bUsedForStore ) 1216 m_bDefaultModified = false; 1217 } 1218 } 1219 } 1220 1221 1222 // ----------------------------------------------------------------------------- 1223 // BinaryOutput, helper class for exportBinary 1224 1225 class BinaryOutput 1226 { 1227 Reference< XMultiComponentFactory > m_xMCF; 1228 Reference< XComponentContext > m_xContext; 1229 Reference< XInterface > m_xTempFile; 1230 Reference< io::XOutputStream > m_xOutputStream; 1231 1232 public: 1233 BinaryOutput( Reference< XMultiComponentFactory > xMCF, 1234 Reference< XComponentContext > xContext ); 1235 1236 Reference< io::XOutputStream > getOutputStream( void ) 1237 { return m_xOutputStream; } 1238 1239 Sequence< ::sal_Int8 > closeAndGetData( void ); 1240 1241 // Template to be used with sal_Int16 and sal_Unicode 1242 template< class T > 1243 void write16BitInt( T n ); 1244 void writeInt16( sal_Int16 n ) 1245 { write16BitInt( n ); } 1246 void writeUnicodeChar( sal_Unicode n ) 1247 { write16BitInt( n ); } 1248 void writeInt32( sal_Int32 n ); 1249 void writeString( const ::rtl::OUString& aStr ); 1250 }; 1251 1252 BinaryOutput::BinaryOutput( Reference< XMultiComponentFactory > xMCF, 1253 Reference< XComponentContext > xContext ) 1254 : m_xMCF( xMCF ) 1255 , m_xContext( xContext ) 1256 { 1257 m_xTempFile = m_xMCF->createInstanceWithContext 1258 ( ::rtl::OUString::createFromAscii( "com.sun.star.io.TempFile" ), m_xContext ); 1259 if( m_xTempFile.is() ) 1260 m_xOutputStream = Reference< io::XOutputStream >( m_xTempFile, UNO_QUERY ); 1261 } 1262 1263 template< class T > 1264 void BinaryOutput::write16BitInt( T n ) 1265 { 1266 if( !m_xOutputStream.is() ) 1267 return; 1268 1269 Sequence< sal_Int8 > aSeq( 2 ); 1270 sal_Int8* p = aSeq.getArray(); 1271 1272 sal_Int8 nLow = sal_Int8( n & 0xff ); 1273 sal_Int8 nHigh = sal_Int8( n >> 8 ); 1274 1275 p[0] = nLow; 1276 p[1] = nHigh; 1277 m_xOutputStream->writeBytes( aSeq ); 1278 } 1279 1280 void BinaryOutput::writeInt32( sal_Int32 n ) 1281 { 1282 if( !m_xOutputStream.is() ) 1283 return; 1284 1285 Sequence< sal_Int8 > aSeq( 4 ); 1286 sal_Int8* p = aSeq.getArray(); 1287 1288 for( sal_Int16 i = 0 ; i < 4 ; i++ ) 1289 { 1290 p[i] = sal_Int8( n & 0xff ); 1291 n >>= 8; 1292 } 1293 m_xOutputStream->writeBytes( aSeq ); 1294 } 1295 1296 void BinaryOutput::writeString( const ::rtl::OUString& aStr ) 1297 { 1298 sal_Int32 nLen = aStr.getLength(); 1299 const sal_Unicode* pStr = aStr.getStr(); 1300 1301 for( sal_Int32 i = 0 ; i < nLen ; i++ ) 1302 writeUnicodeChar( pStr[i] ); 1303 1304 writeUnicodeChar( 0 ); 1305 } 1306 1307 Sequence< ::sal_Int8 > BinaryOutput::closeAndGetData( void ) 1308 { 1309 Sequence< ::sal_Int8 > aRetSeq; 1310 if( !m_xOutputStream.is() ) 1311 return aRetSeq; 1312 1313 m_xOutputStream->closeOutput(); 1314 1315 Reference< io::XSeekable> xSeekable( m_xTempFile, UNO_QUERY ); 1316 if( !xSeekable.is() ) 1317 return aRetSeq; 1318 1319 sal_Int32 nSize = (sal_Int32)xSeekable->getPosition(); 1320 1321 Reference< io::XInputStream> xInputStream( m_xTempFile, UNO_QUERY ); 1322 if( !xInputStream.is() ) 1323 return aRetSeq; 1324 1325 xSeekable->seek( 0 ); 1326 sal_Int32 nRead = xInputStream->readBytes( aRetSeq, nSize ); 1327 (void)nRead; 1328 OSL_ENSURE( nRead == nSize, "BinaryOutput::closeAndGetData: nRead != nSize" ); 1329 1330 return aRetSeq; 1331 } 1332 1333 1334 // Binary format: 1335 1336 // Header 1337 // Byte Content 1338 // 0 + 1 sal_Int16: Version, currently 0, low byte first 1339 // 2 + 3 sal_Int16: Locale count = n, low byte first 1340 // 4 + 5 sal_Int16: Default Locale position in Locale list, == n if none 1341 // 6 - 7 sal_Int32: Start index locale block 0, lowest byte first 1342 // (n-1) * sal_Int32: Start index locale block 1 to n, lowest byte first 1343 // 6 + 4*n sal_Int32: "Start index" non existing locale block n+1, 1344 // marks the first invalid index, kind of EOF 1345 1346 // Locale block 1347 // All strings are stored as 2-Byte-0 terminated sequence 1348 // of 16 bit Unicode characters, each with low byte first 1349 // Empty strings only contain the 2-Byte-0 1350 1351 // Members of com.sun.star.lang.Locale 1352 // with l1 = Locale.Language.getLength() 1353 // with l2 = Locale.Country.getLength() 1354 // with l3 = Locale.Variant.getLength() 1355 // pos0 = 0 Locale.Language 1356 // pos1 = 2 * (l1 + 1) Locale.Country 1357 // pos2 = pos1 + 2 * (l2 + 1) Locale.Variant 1358 // pos3 = pos2 + 2 * (l3 + 1) 1359 // pos3 Properties file written by implWritePropertiesFile 1360 1361 Sequence< sal_Int8 > StringResourcePersistenceImpl::exportBinary( ) 1362 { 1363 Reference< XMultiComponentFactory > xMCF = getMultiComponentFactory(); 1364 BinaryOutput aOut( xMCF, m_xContext ); 1365 1366 sal_Int32 nLocaleCount = m_aLocaleItemVector.size(); 1367 Sequence< sal_Int8 >* pLocaleDataSeq = new Sequence< sal_Int8 >[ nLocaleCount ]; 1368 1369 sal_Int32 iLocale = 0; 1370 sal_Int32 iDefault = 0; 1371 for( LocaleItemVectorConstIt it = m_aLocaleItemVector.begin(); 1372 it != m_aLocaleItemVector.end(); it++,iLocale++ ) 1373 { 1374 LocaleItem* pLocaleItem = *it; 1375 if( pLocaleItem != NULL && loadLocale( pLocaleItem ) ) 1376 { 1377 if( m_pDefaultLocaleItem == pLocaleItem ) 1378 iDefault = iLocale; 1379 1380 BinaryOutput aLocaleOut( m_xMCF, m_xContext ); 1381 implWriteLocaleBinary( pLocaleItem, aLocaleOut ); 1382 1383 pLocaleDataSeq[iLocale] = aLocaleOut.closeAndGetData(); 1384 } 1385 } 1386 1387 // Write header 1388 sal_Int16 nVersion = 0; 1389 sal_Int16 nLocaleCount16 = (sal_Int16)nLocaleCount; 1390 sal_Int16 iDefault16 = (sal_Int16)iDefault; 1391 aOut.writeInt16( nVersion ); 1392 aOut.writeInt16( nLocaleCount16 ); 1393 aOut.writeInt16( iDefault16 ); 1394 1395 // Write data positions 1396 sal_Int32 nDataPos = 6 + 4 * (nLocaleCount + 1); 1397 for( iLocale = 0; iLocale < nLocaleCount; iLocale++ ) 1398 { 1399 aOut.writeInt32( nDataPos ); 1400 1401 Sequence< sal_Int8 >& rSeq = pLocaleDataSeq[iLocale]; 1402 sal_Int32 nSeqLen = rSeq.getLength(); 1403 nDataPos += nSeqLen; 1404 } 1405 // Write final position 1406 aOut.writeInt32( nDataPos ); 1407 1408 // Write data 1409 Reference< io::XOutputStream > xOutputStream = aOut.getOutputStream(); 1410 if( xOutputStream.is() ) 1411 { 1412 for( iLocale = 0; iLocale < nLocaleCount; iLocale++ ) 1413 { 1414 Sequence< sal_Int8 >& rSeq = pLocaleDataSeq[iLocale]; 1415 xOutputStream->writeBytes( rSeq ); 1416 } 1417 } 1418 1419 delete[] pLocaleDataSeq; 1420 1421 Sequence< sal_Int8 > aRetSeq = aOut.closeAndGetData(); 1422 return aRetSeq; 1423 } 1424 1425 void StringResourcePersistenceImpl::implWriteLocaleBinary 1426 ( LocaleItem* pLocaleItem, BinaryOutput& rOut ) 1427 { 1428 Reference< io::XOutputStream > xOutputStream = rOut.getOutputStream(); 1429 if( !xOutputStream.is() ) 1430 return; 1431 1432 Locale& rLocale = pLocaleItem->m_locale; 1433 rOut.writeString( rLocale.Language ); 1434 rOut.writeString( rLocale.Country ); 1435 rOut.writeString( rLocale.Variant ); 1436 implWritePropertiesFile( pLocaleItem, xOutputStream, m_aComment ); 1437 } 1438 1439 // ----------------------------------------------------------------------------- 1440 // BinaryOutput, helper class for exportBinary 1441 1442 class BinaryInput 1443 { 1444 Sequence< sal_Int8 > m_aData; 1445 Reference< XMultiComponentFactory > m_xMCF; 1446 Reference< XComponentContext > m_xContext; 1447 1448 const sal_Int8* m_pData; 1449 sal_Int32 m_nCurPos; 1450 sal_Int32 m_nSize; 1451 1452 public: 1453 BinaryInput( Sequence< ::sal_Int8 > aData, Reference< XMultiComponentFactory > xMCF, 1454 Reference< XComponentContext > xContext ); 1455 1456 Reference< io::XInputStream > getInputStreamForSection( sal_Int32 nSize ); 1457 1458 void seek( sal_Int32 nPos ); 1459 sal_Int32 getPosition( void ) 1460 { return m_nCurPos; } 1461 1462 sal_Int16 readInt16( void ); 1463 sal_Int32 readInt32( void ); 1464 sal_Unicode readUnicodeChar( void ); 1465 ::rtl::OUString readString( void ); 1466 }; 1467 1468 BinaryInput::BinaryInput( Sequence< ::sal_Int8 > aData, Reference< XMultiComponentFactory > xMCF, 1469 Reference< XComponentContext > xContext ) 1470 : m_aData( aData ) 1471 , m_xMCF( xMCF ) 1472 , m_xContext( xContext ) 1473 { 1474 m_pData = m_aData.getConstArray(); 1475 m_nCurPos = 0; 1476 m_nSize = m_aData.getLength(); 1477 } 1478 1479 Reference< io::XInputStream > BinaryInput::getInputStreamForSection( sal_Int32 nSize ) 1480 { 1481 Reference< io::XInputStream > xIn; 1482 if( m_nCurPos + nSize <= m_nSize ) 1483 { 1484 Reference< io::XOutputStream > xTempOut( m_xMCF->createInstanceWithContext 1485 ( ::rtl::OUString::createFromAscii( "com.sun.star.io.TempFile" ), m_xContext ), UNO_QUERY ); 1486 if( xTempOut.is() ) 1487 { 1488 Sequence< sal_Int8 > aSection( m_pData + m_nCurPos, nSize ); 1489 xTempOut->writeBytes( aSection ); 1490 1491 Reference< io::XSeekable> xSeekable( xTempOut, UNO_QUERY ); 1492 if( xSeekable.is() ) 1493 xSeekable->seek( 0 ); 1494 1495 xIn = Reference< io::XInputStream>( xTempOut, UNO_QUERY ); 1496 } 1497 } 1498 else 1499 OSL_ENSURE( false, "BinaryInput::getInputStreamForSection(): Read past end" ); 1500 1501 return xIn; 1502 } 1503 1504 void BinaryInput::seek( sal_Int32 nPos ) 1505 { 1506 if( nPos <= m_nSize ) 1507 m_nCurPos = nPos; 1508 else 1509 OSL_ENSURE( false, "BinaryInput::seek(): Position past end" ); 1510 } 1511 1512 1513 sal_Int16 BinaryInput::readInt16( void ) 1514 { 1515 sal_Int16 nRet = 0; 1516 if( m_nCurPos + 2 <= m_nSize ) 1517 { 1518 nRet = nRet + sal_Int16( sal_uInt8( m_pData[m_nCurPos++] ) ); 1519 nRet += 256 * sal_Int16( sal_uInt8( m_pData[m_nCurPos++] ) ); 1520 } 1521 else 1522 OSL_ENSURE( false, "BinaryInput::readInt16(): Read past end" ); 1523 1524 return nRet; 1525 } 1526 1527 sal_Int32 BinaryInput::readInt32( void ) 1528 { 1529 sal_Int32 nRet = 0; 1530 if( m_nCurPos + 4 <= m_nSize ) 1531 { 1532 sal_Int32 nFactor = 1; 1533 for( sal_Int16 i = 0; i < 4; i++ ) 1534 { 1535 nRet += sal_uInt8( m_pData[m_nCurPos++] ) * nFactor; 1536 nFactor *= 256; 1537 } 1538 } 1539 else 1540 OSL_ENSURE( false, "BinaryInput::readInt32(): Read past end" ); 1541 1542 return nRet; 1543 } 1544 1545 sal_Unicode BinaryInput::readUnicodeChar( void ) 1546 { 1547 sal_uInt16 nRet = 0; 1548 if( m_nCurPos + 2 <= m_nSize ) 1549 { 1550 nRet = nRet + sal_uInt8( m_pData[m_nCurPos++] ); 1551 nRet += 256 * sal_uInt8( m_pData[m_nCurPos++] ); 1552 } 1553 else 1554 OSL_ENSURE( false, "BinaryInput::readUnicodeChar(): Read past end" ); 1555 1556 sal_Unicode cRet = nRet; 1557 return cRet; 1558 } 1559 1560 ::rtl::OUString BinaryInput::readString( void ) 1561 { 1562 ::rtl::OUStringBuffer aBuf; 1563 sal_Unicode c; 1564 do 1565 { 1566 c = readUnicodeChar(); 1567 if( c != 0 ) 1568 aBuf.append( c ); 1569 } 1570 while( c != 0 ); 1571 1572 ::rtl::OUString aRetStr = aBuf.makeStringAndClear(); 1573 return aRetStr; 1574 } 1575 1576 void StringResourcePersistenceImpl::importBinary( const Sequence< ::sal_Int8 >& Data ) 1577 { 1578 // Init: Remove all locales 1579 sal_Int32 nOldLocaleCount = 0; 1580 do 1581 { 1582 Sequence< Locale > aLocaleSeq = getLocales(); 1583 nOldLocaleCount = aLocaleSeq.getLength(); 1584 if( nOldLocaleCount > 0 ) 1585 { 1586 Locale aLocale = aLocaleSeq[0]; 1587 removeLocale( aLocale ); 1588 } 1589 } 1590 while( nOldLocaleCount > 0 ); 1591 1592 // Import data 1593 Reference< XMultiComponentFactory > xMCF = getMultiComponentFactory(); 1594 BinaryInput aIn( Data, xMCF, m_xContext ); 1595 1596 sal_Int32 nVersion = aIn.readInt16(); 1597 (void)nVersion; 1598 sal_Int32 nLocaleCount = aIn.readInt16(); 1599 sal_Int32 iDefault = aIn.readInt16(); 1600 (void)iDefault; 1601 1602 sal_Int32* pPositions = new sal_Int32[nLocaleCount + 1]; 1603 for( sal_Int32 i = 0; i < nLocaleCount + 1; i++ ) 1604 pPositions[i] = aIn.readInt32(); 1605 1606 // Import locales 1607 LocaleItem* pUseAsDefaultItem = NULL; 1608 for( sal_Int32 i = 0; i < nLocaleCount; i++ ) 1609 { 1610 sal_Int32 nPos = pPositions[i]; 1611 aIn.seek( nPos ); 1612 1613 Locale aLocale; 1614 aLocale.Language = aIn.readString(); 1615 aLocale.Country = aIn.readString(); 1616 aLocale.Variant = aIn.readString(); 1617 1618 sal_Int32 nAfterStringPos = aIn.getPosition(); 1619 sal_Int32 nSize = pPositions[i+1] - nAfterStringPos; 1620 Reference< io::XInputStream > xInput = aIn.getInputStreamForSection( nSize ); 1621 if( xInput.is() ) 1622 { 1623 LocaleItem* pLocaleItem = new LocaleItem( aLocale ); 1624 if( iDefault == i ) 1625 pUseAsDefaultItem = pLocaleItem; 1626 m_aLocaleItemVector.push_back( pLocaleItem ); 1627 implReadPropertiesFile( pLocaleItem, xInput ); 1628 } 1629 } 1630 1631 if( pUseAsDefaultItem != NULL ) 1632 setDefaultLocale( pUseAsDefaultItem->m_locale ); 1633 1634 delete[] pPositions; 1635 } 1636 1637 1638 // ============================================================================= 1639 // Private helper methods 1640 1641 bool checkNamingSceme( const ::rtl::OUString& aName, const ::rtl::OUString& aNameBase, 1642 Locale& aLocale ) 1643 { 1644 bool bSuccess = false; 1645 1646 sal_Int32 nNameLen = aName.getLength(); 1647 sal_Int32 nNameBaseLen = aNameBase.getLength(); 1648 1649 // Name has to start with NameBase followed 1650 // by a '_' and at least one more character 1651 if( aName.indexOf( aNameBase ) == 0 && nNameBaseLen < nNameLen-1 && 1652 aName.getStr()[nNameBaseLen] == '_' ) 1653 { 1654 bSuccess = true; 1655 1656 sal_Int32 iStart = nNameBaseLen + 1; 1657 sal_Int32 iNext_ = aName.indexOf( '_', iStart ); 1658 if( iNext_ != -1 && iNext_ < nNameLen-1 ) 1659 { 1660 aLocale.Language = aName.copy( iStart, iNext_ - iStart ); 1661 1662 iStart = iNext_ + 1; 1663 iNext_ = aName.indexOf( '_', iStart ); 1664 if( iNext_ != -1 && iNext_ < nNameLen-1 ) 1665 { 1666 aLocale.Country = aName.copy( iStart, iNext_ - iStart ); 1667 aLocale.Variant = aName.copy( iNext_ + 1 ); 1668 } 1669 else 1670 aLocale.Country = aName.copy( iStart ); 1671 } 1672 else 1673 aLocale.Language = aName.copy( iStart ); 1674 } 1675 return bSuccess; 1676 } 1677 1678 void StringResourcePersistenceImpl::implLoadAllLocales( void ) 1679 { 1680 for( LocaleItemVectorIt it = m_aLocaleItemVector.begin(); it != m_aLocaleItemVector.end(); it++ ) 1681 { 1682 LocaleItem* pLocaleItem = *it; 1683 if( pLocaleItem != NULL ) 1684 loadLocale( pLocaleItem ); 1685 } 1686 } 1687 1688 // Scan locale properties files helper 1689 void StringResourcePersistenceImpl::implScanLocaleNames( const Sequence< ::rtl::OUString >& aContentSeq ) 1690 { 1691 Locale aDefaultLocale; 1692 bool bDefaultFound = false; 1693 1694 sal_Int32 nCount = aContentSeq.getLength(); 1695 const ::rtl::OUString* pFiles = aContentSeq.getConstArray(); 1696 for( int i = 0 ; i < nCount ; i++ ) 1697 { 1698 ::rtl::OUString aCompleteName = pFiles[i]; 1699 rtl::OUString aPureName; 1700 rtl::OUString aExtension; 1701 sal_Int32 iDot = aCompleteName.lastIndexOf( '.' ); 1702 sal_Int32 iSlash = aCompleteName.lastIndexOf( '/' ); 1703 if( iDot != -1 ) 1704 { 1705 sal_Int32 iCopyFrom = (iSlash != -1) ? iSlash + 1 : 0; 1706 aPureName = aCompleteName.copy( iCopyFrom, iDot-iCopyFrom ); 1707 aExtension = aCompleteName.copy( iDot + 1 ); 1708 } 1709 1710 if( aExtension.equalsAscii( "properties" ) ) 1711 { 1712 //rtl::OUString aName = aInetObj.getBase(); 1713 Locale aLocale; 1714 1715 if( checkNamingSceme( aPureName, m_aNameBase, aLocale ) ) 1716 { 1717 LocaleItem* pLocaleItem = new LocaleItem( aLocale, false ); 1718 m_aLocaleItemVector.push_back( pLocaleItem ); 1719 1720 if( m_pCurrentLocaleItem == NULL ) 1721 m_pCurrentLocaleItem = pLocaleItem; 1722 1723 if( m_pDefaultLocaleItem == NULL ) 1724 { 1725 m_pDefaultLocaleItem = pLocaleItem; 1726 m_bDefaultModified = true; 1727 } 1728 } 1729 } 1730 else if( !bDefaultFound && aExtension.equalsAscii( "default" ) ) 1731 { 1732 //rtl::OUString aName = aInetObj.getBase(); 1733 Locale aLocale; 1734 1735 if( checkNamingSceme( aPureName, m_aNameBase, aDefaultLocale ) ) 1736 bDefaultFound = true; 1737 } 1738 } 1739 if( bDefaultFound ) 1740 { 1741 LocaleItem* pLocaleItem = getItemForLocale( aDefaultLocale, false ); 1742 if( pLocaleItem ) 1743 { 1744 m_pDefaultLocaleItem = pLocaleItem; 1745 m_bDefaultModified = false; 1746 } 1747 } 1748 } 1749 1750 // Scan locale properties files 1751 void StringResourcePersistenceImpl::implScanLocales( void ) 1752 { 1753 // Dummy implementation, method not called for this 1754 // base class, but pure virtual not possible- 1755 } 1756 1757 bool StringResourcePersistenceImpl::loadLocale( LocaleItem* pLocaleItem ) 1758 { 1759 bool bSuccess = false; 1760 1761 OSL_ENSURE( pLocaleItem, "StringResourcePersistenceImpl::loadLocale(): pLocaleItem == NULL" ); 1762 if( pLocaleItem ) 1763 { 1764 if( pLocaleItem->m_bLoaded ) 1765 { 1766 bSuccess = true; 1767 } 1768 else 1769 { 1770 bSuccess = implLoadLocale( pLocaleItem ); 1771 pLocaleItem->m_bLoaded = true; // = bSuccess??? -> leads to more tries 1772 } 1773 } 1774 return bSuccess; 1775 } 1776 1777 bool StringResourcePersistenceImpl::implLoadLocale( LocaleItem* ) 1778 { 1779 // Dummy implementation, method not called for this 1780 // base class, but pure virtual not possible- 1781 return false; 1782 } 1783 1784 ::rtl::OUString implGetNameScemeForLocaleItem( const LocaleItem* pLocaleItem ) 1785 { 1786 static ::rtl::OUString aUnder = ::rtl::OUString::createFromAscii( "_" ); 1787 1788 OSL_ENSURE( pLocaleItem, 1789 "StringResourcePersistenceImpl::implGetNameScemeForLocaleItem(): pLocaleItem == NULL" ); 1790 Locale aLocale = pLocaleItem->m_locale; 1791 1792 ::rtl::OUString aRetStr = aUnder; 1793 aRetStr += aLocale.Language; 1794 1795 ::rtl::OUString aCountry = aLocale.Country; 1796 if( aCountry.getLength() ) 1797 { 1798 aRetStr += aUnder; 1799 aRetStr += aCountry; 1800 } 1801 1802 ::rtl::OUString aVariant = aLocale.Variant; 1803 if( aVariant.getLength() ) 1804 { 1805 aRetStr += aUnder; 1806 aRetStr += aVariant; 1807 } 1808 return aRetStr; 1809 } 1810 1811 ::rtl::OUString StringResourcePersistenceImpl::implGetFileNameForLocaleItem 1812 ( LocaleItem* pLocaleItem, const ::rtl::OUString& aNameBase ) 1813 { 1814 ::rtl::OUString aFileName = aNameBase; 1815 if( aFileName.getLength() == 0 ) 1816 aFileName = aNameBaseDefaultStr; 1817 1818 aFileName += implGetNameScemeForLocaleItem( pLocaleItem ); 1819 return aFileName; 1820 } 1821 1822 ::rtl::OUString StringResourcePersistenceImpl::implGetPathForLocaleItem 1823 ( LocaleItem* pLocaleItem, const ::rtl::OUString& aNameBase, 1824 const ::rtl::OUString& aLocation, bool bDefaultFile ) 1825 { 1826 ::rtl::OUString aFileName = implGetFileNameForLocaleItem( pLocaleItem, aNameBase ); 1827 INetURLObject aInetObj( aLocation ); 1828 aInetObj.insertName( aFileName, sal_True, INetURLObject::LAST_SEGMENT, sal_True, INetURLObject::ENCODE_ALL ); 1829 if( bDefaultFile ) 1830 aInetObj.setExtension( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("default") ) ); 1831 else 1832 aInetObj.setExtension( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("properties") ) ); 1833 ::rtl::OUString aCompleteFileName = aInetObj.GetMainURL( INetURLObject::NO_DECODE ); 1834 return aCompleteFileName; 1835 } 1836 1837 // White space according to Java property files specification in 1838 // http://java.sun.com/j2se/1.4.2/docs/api/java/util/Properties.html#load(java.io.InputStream) 1839 inline bool isWhiteSpace( sal_Unicode c ) 1840 { 1841 bool bWhite = ( c == 0x0020 || // space 1842 c == 0x0009 || // tab 1843 c == 0x000a || // line feed, not always handled by TextInputStream 1844 c == 0x000d || // carriage return, not always handled by TextInputStream 1845 c == 0x000C ); // form feed 1846 return bWhite; 1847 } 1848 1849 inline void skipWhites( const sal_Unicode* pBuf, sal_Int32 nLen, sal_Int32& ri ) 1850 { 1851 while( ri < nLen ) 1852 { 1853 if( !isWhiteSpace( pBuf[ri] ) ) 1854 break; 1855 ri++; 1856 } 1857 } 1858 1859 inline bool isHexDigit( sal_Unicode c, sal_uInt16& nDigitVal ) 1860 { 1861 bool bRet = true; 1862 if( c >= '0' && c <= '9' ) 1863 nDigitVal = c - '0'; 1864 else if( c >= 'a' && c <= 'f' ) 1865 nDigitVal = c - 'a' + 10; 1866 else if( c >= 'A' && c <= 'F' ) 1867 nDigitVal = c - 'A' + 10; 1868 else 1869 bRet = false; 1870 return bRet; 1871 } 1872 1873 sal_Unicode getEscapeChar( const sal_Unicode* pBuf, sal_Int32 nLen, sal_Int32& ri ) 1874 { 1875 sal_Int32 i = ri; 1876 1877 sal_Unicode cRet = 0; 1878 sal_Unicode c = pBuf[i]; 1879 switch( c ) 1880 { 1881 case 't': 1882 cRet = 0x0009; 1883 break; 1884 case 'n': 1885 cRet = 0x000a; 1886 break; 1887 case 'f': 1888 cRet = 0x000c; 1889 break; 1890 case 'r': 1891 cRet = 0x000d; 1892 break; 1893 case '\\': 1894 cRet = '\\'; 1895 break; 1896 case 'u': 1897 { 1898 // Skip multiple u 1899 i++; 1900 while( i < nLen && pBuf[i] == 'u' ) 1901 i++; 1902 1903 // Process hex digits 1904 sal_Int32 nDigitCount = 0; 1905 sal_uInt16 nDigitVal; 1906 while( i < nLen && isHexDigit( pBuf[i], nDigitVal ) ) 1907 { 1908 cRet = 16 * cRet + nDigitVal; 1909 1910 nDigitCount++; 1911 if( nDigitCount == 4 ) 1912 { 1913 // Write back position 1914 ri = i; 1915 break; 1916 } 1917 i++; 1918 } 1919 break; 1920 } 1921 default: 1922 cRet = c; 1923 } 1924 1925 return cRet; 1926 } 1927 1928 void CheckContinueInNextLine( Reference< io::XTextInputStream > xTextInputStream, 1929 ::rtl::OUString& aLine, bool& bEscapePending, const sal_Unicode*& pBuf, 1930 sal_Int32& nLen, sal_Int32& i ) 1931 { 1932 if( i == nLen && bEscapePending ) 1933 { 1934 bEscapePending = false; 1935 1936 if( !xTextInputStream->isEOF() ) 1937 { 1938 aLine = xTextInputStream->readLine(); 1939 nLen = aLine.getLength(); 1940 pBuf = aLine.getStr(); 1941 i = 0; 1942 1943 skipWhites( pBuf, nLen, i ); 1944 } 1945 } 1946 } 1947 1948 bool StringResourcePersistenceImpl::implReadPropertiesFile 1949 ( LocaleItem* pLocaleItem, const Reference< io::XInputStream >& xInputStream ) 1950 { 1951 if( !xInputStream.is() || pLocaleItem == NULL ) 1952 return false; 1953 1954 bool bSuccess = false; 1955 Reference< XMultiComponentFactory > xMCF = getMultiComponentFactory(); 1956 Reference< io::XTextInputStream > xTextInputStream( xMCF->createInstanceWithContext 1957 ( ::rtl::OUString::createFromAscii( "com.sun.star.io.TextInputStream" ), m_xContext ), UNO_QUERY ); 1958 1959 if( xTextInputStream.is() ) 1960 { 1961 Reference< io::XActiveDataSink> xActiveDataSink( xTextInputStream, UNO_QUERY ); 1962 if( xActiveDataSink.is() ) 1963 { 1964 bSuccess = true; 1965 1966 xActiveDataSink->setInputStream( xInputStream ); 1967 1968 ::rtl::OUString aEncodingStr = ::rtl::OUString::createFromAscii 1969 ( rtl_getMimeCharsetFromTextEncoding( RTL_TEXTENCODING_ISO_8859_1 ) ); 1970 xTextInputStream->setEncoding( aEncodingStr ); 1971 1972 ::rtl::OUString aLine; 1973 while( !xTextInputStream->isEOF() ) 1974 { 1975 aLine = xTextInputStream->readLine(); 1976 1977 sal_Int32 nLen = aLine.getLength(); 1978 if( 0 == nLen ) 1979 continue; 1980 const sal_Unicode* pBuf = aLine.getStr(); 1981 ::rtl::OUStringBuffer aBuf; 1982 sal_Unicode c = 0; 1983 sal_Int32 i = 0; 1984 1985 skipWhites( pBuf, nLen, i ); 1986 if( i == nLen ) 1987 continue; // line contains only white spaces 1988 1989 // Comment? 1990 c = pBuf[i]; 1991 if( c == '#' || c == '!' ) 1992 continue; 1993 1994 // Scan key 1995 ::rtl::OUString aResourceID; 1996 bool bEscapePending = false; 1997 bool bStrComplete = false; 1998 while( i < nLen && !bStrComplete ) 1999 { 2000 c = pBuf[i]; 2001 if( bEscapePending ) 2002 { 2003 aBuf.append( getEscapeChar( pBuf, nLen, i ) ); 2004 bEscapePending = false; 2005 } 2006 else 2007 { 2008 if( c == '\\' ) 2009 { 2010 bEscapePending = true; 2011 } 2012 else 2013 { 2014 if( c == ':' || c == '=' || isWhiteSpace( c ) ) 2015 bStrComplete = true; 2016 else 2017 aBuf.append( c ); 2018 } 2019 } 2020 i++; 2021 2022 CheckContinueInNextLine( xTextInputStream, aLine, bEscapePending, pBuf, nLen, i ); 2023 if( i == nLen ) 2024 bStrComplete = true; 2025 2026 if( bStrComplete ) 2027 aResourceID = aBuf.makeStringAndClear(); 2028 } 2029 2030 // Ignore lines with empty keys 2031 if( 0 == aResourceID.getLength() ) 2032 continue; 2033 2034 // Scan value 2035 skipWhites( pBuf, nLen, i ); 2036 2037 ::rtl::OUString aValueStr; 2038 bEscapePending = false; 2039 bStrComplete = false; 2040 while( i < nLen && !bStrComplete ) 2041 { 2042 c = pBuf[i]; 2043 if( c == 0x000a || c == 0x000d ) // line feed/carriage return, not always handled by TextInputStream 2044 { 2045 i++; 2046 } 2047 else 2048 { 2049 if( bEscapePending ) 2050 { 2051 aBuf.append( getEscapeChar( pBuf, nLen, i ) ); 2052 bEscapePending = false; 2053 } 2054 else if( c == '\\' ) 2055 bEscapePending = true; 2056 else 2057 aBuf.append( c ); 2058 i++; 2059 2060 CheckContinueInNextLine( xTextInputStream, aLine, bEscapePending, pBuf, nLen, i ); 2061 } 2062 if( i == nLen ) 2063 bStrComplete = true; 2064 2065 if( bStrComplete ) 2066 aValueStr = aBuf.makeStringAndClear(); 2067 } 2068 2069 // Push into table 2070 pLocaleItem->m_aIdToStringMap[ aResourceID ] = aValueStr; 2071 implScanIdForNumber( aResourceID ); 2072 IdToIndexMap& rIndexMap = pLocaleItem->m_aIdToIndexMap; 2073 rIndexMap[ aResourceID ] = pLocaleItem->m_nNextIndex++; 2074 } 2075 } 2076 } 2077 2078 return bSuccess; 2079 } 2080 2081 2082 inline sal_Unicode getHexCharForDigit( sal_uInt16 nDigitVal ) 2083 { 2084 sal_Unicode cRet = ( nDigitVal < 10 ) ? ('0' + nDigitVal) : ('a' + (nDigitVal-10)); 2085 return cRet; 2086 } 2087 2088 void implWriteCharToBuffer( ::rtl::OUStringBuffer& aBuf, sal_Unicode cu, bool bKey ) 2089 { 2090 if( cu == '\\' ) 2091 { 2092 aBuf.append( (sal_Unicode)'\\' ); 2093 aBuf.append( (sal_Unicode)'\\' ); 2094 } 2095 else if( cu == 0x000a ) 2096 { 2097 aBuf.append( (sal_Unicode)'\\' ); 2098 aBuf.append( (sal_Unicode)'n' ); 2099 } 2100 else if( cu == 0x000d ) 2101 { 2102 aBuf.append( (sal_Unicode)'\\' ); 2103 aBuf.append( (sal_Unicode)'r' ); 2104 } 2105 else if( bKey && cu == '=' ) 2106 { 2107 aBuf.append( (sal_Unicode)'\\' ); 2108 aBuf.append( (sal_Unicode)'=' ); 2109 } 2110 else if( bKey && cu == ':' ) 2111 { 2112 aBuf.append( (sal_Unicode)'\\' ); 2113 aBuf.append( (sal_Unicode)':' ); 2114 } 2115 // ISO/IEC 8859-1 range according to: 2116 // http://en.wikipedia.org/wiki/ISO/IEC_8859-1 2117 else if( (cu >= 0x20 && cu <= 0x7e) ) 2118 //TODO: Check why (cu >= 0xa0 && cu <= 0xFF) 2119 //is encoded in sample properties files 2120 //else if( (cu >= 0x20 && cu <= 0x7e) || 2121 // (cu >= 0xa0 && cu <= 0xFF) ) 2122 { 2123 aBuf.append( cu ); 2124 } 2125 else 2126 { 2127 // Unicode encoding 2128 aBuf.append( (sal_Unicode)'\\' ); 2129 aBuf.append( (sal_Unicode)'u' ); 2130 2131 sal_uInt16 nVal = cu; 2132 for( sal_uInt16 i = 0 ; i < 4 ; i++ ) 2133 { 2134 sal_uInt16 nDigit = nVal / 0x1000; 2135 nVal -= nDigit * 0x1000; 2136 nVal *= 0x10; 2137 aBuf.append( getHexCharForDigit( nDigit ) ); 2138 } 2139 } 2140 } 2141 2142 void implWriteStringWithEncoding( const ::rtl::OUString& aStr, 2143 Reference< io::XTextOutputStream > xTextOutputStream, bool bKey ) 2144 { 2145 static sal_Unicode cLineFeed = 0xa; 2146 2147 (void)aStr; 2148 (void)xTextOutputStream; 2149 2150 ::rtl::OUStringBuffer aBuf; 2151 sal_Int32 nLen = aStr.getLength(); 2152 const sal_Unicode* pSrc = aStr.getStr(); 2153 for( sal_Int32 i = 0 ; i < nLen ; i++ ) 2154 { 2155 sal_Unicode cu = pSrc[i]; 2156 implWriteCharToBuffer( aBuf, cu, bKey ); 2157 // TODO?: split long lines 2158 } 2159 if( !bKey ) 2160 aBuf.append( cLineFeed ); 2161 2162 ::rtl::OUString aWriteStr = aBuf.makeStringAndClear(); 2163 xTextOutputStream->writeString( aWriteStr ); 2164 } 2165 2166 bool StringResourcePersistenceImpl::implWritePropertiesFile( LocaleItem* pLocaleItem, 2167 const Reference< io::XOutputStream >& xOutputStream, const ::rtl::OUString& aComment ) 2168 { 2169 static ::rtl::OUString aAssignmentStr = ::rtl::OUString::createFromAscii( "=" ); 2170 static ::rtl::OUString aLineFeedStr = ::rtl::OUString::createFromAscii( "\n" ); 2171 2172 if( !xOutputStream.is() || pLocaleItem == NULL ) 2173 return false; 2174 2175 bool bSuccess = false; 2176 Reference< XMultiComponentFactory > xMCF = getMultiComponentFactory(); 2177 Reference< io::XTextOutputStream > xTextOutputStream( xMCF->createInstanceWithContext 2178 ( ::rtl::OUString::createFromAscii( "com.sun.star.io.TextOutputStream" ), m_xContext ), UNO_QUERY ); 2179 2180 if( xTextOutputStream.is() ) 2181 { 2182 Reference< io::XActiveDataSource> xActiveDataSource( xTextOutputStream, UNO_QUERY ); 2183 if( xActiveDataSource.is() ) 2184 { 2185 xActiveDataSource->setOutputStream( xOutputStream ); 2186 2187 ::rtl::OUString aEncodingStr = ::rtl::OUString::createFromAscii 2188 ( rtl_getMimeCharsetFromTextEncoding( RTL_TEXTENCODING_ISO_8859_1 ) ); 2189 xTextOutputStream->setEncoding( aEncodingStr ); 2190 2191 xTextOutputStream->writeString( aComment ); 2192 xTextOutputStream->writeString( aLineFeedStr ); 2193 2194 const IdToStringMap& rHashMap = pLocaleItem->m_aIdToStringMap; 2195 if( rHashMap.size() > 0 ) 2196 { 2197 // Sort ids according to read order 2198 const IdToIndexMap& rIndexMap = pLocaleItem->m_aIdToIndexMap; 2199 IdToIndexMap::const_iterator it_index; 2200 2201 // Find max/min index 2202 sal_Int32 nMinIndex = -1; 2203 sal_Int32 nMaxIndex = -1; 2204 for( it_index = rIndexMap.begin(); it_index != rIndexMap.end(); it_index++ ) 2205 { 2206 sal_Int32 nIndex = (*it_index).second; 2207 if( nMinIndex > nIndex || nMinIndex == -1 ) 2208 nMinIndex = nIndex; 2209 if( nMaxIndex < nIndex ) 2210 nMaxIndex = nIndex; 2211 } 2212 sal_Int32 nTabSize = nMaxIndex - nMinIndex + 1; 2213 2214 // Create sorted array of pointers to the id strings 2215 const ::rtl::OUString** pIdPtrs = new const ::rtl::OUString*[nTabSize]; 2216 sal_Int32 i; 2217 for( i = 0 ; i < nTabSize ; i++ ) 2218 pIdPtrs[i] = NULL; 2219 for( it_index = rIndexMap.begin(); it_index != rIndexMap.end(); it_index++ ) 2220 { 2221 sal_Int32 nIndex = (*it_index).second; 2222 pIdPtrs[nIndex - nMinIndex] = &((*it_index).first); 2223 } 2224 2225 // Write lines in correct order 2226 for( i = 0 ; i < nTabSize ; i++ ) 2227 { 2228 const ::rtl::OUString* pStr = pIdPtrs[i]; 2229 if( pStr != NULL ) 2230 { 2231 ::rtl::OUString aResourceID = *pStr; 2232 IdToStringMap::const_iterator it = rHashMap.find( aResourceID ); 2233 if( !( it == rHashMap.end() ) ) 2234 { 2235 implWriteStringWithEncoding( aResourceID, xTextOutputStream, true ); 2236 xTextOutputStream->writeString( aAssignmentStr ); 2237 ::rtl::OUString aValStr = (*it).second; 2238 implWriteStringWithEncoding( aValStr, xTextOutputStream, false ); 2239 } 2240 } 2241 } 2242 2243 delete[] pIdPtrs; 2244 } 2245 2246 bSuccess = true; 2247 } 2248 } 2249 return bSuccess; 2250 } 2251 2252 2253 // ============================================================================= 2254 // StringResourceWithStorageImpl 2255 // ============================================================================= 2256 2257 // component operations 2258 static Sequence< ::rtl::OUString > getSupportedServiceNames_StringResourceWithStorageImpl() 2259 { 2260 Sequence< ::rtl::OUString > names(1); 2261 names[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.resource.StringResourceWithStorage") ); 2262 return names; 2263 } 2264 2265 static ::rtl::OUString getImplementationName_StringResourceWithStorageImpl() 2266 { 2267 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.scripting.StringResourceWithStorage") ); 2268 } 2269 2270 static Reference< XInterface > SAL_CALL create_StringResourceWithStorageImpl( 2271 Reference< XComponentContext > const & xContext ) 2272 SAL_THROW( () ) 2273 { 2274 return static_cast< ::cppu::OWeakObject * >( new StringResourceWithStorageImpl( xContext ) ); 2275 } 2276 2277 // ----------------------------------------------------------------------------- 2278 2279 StringResourceWithStorageImpl::StringResourceWithStorageImpl( const Reference< XComponentContext >& rxContext ) 2280 : StringResourceWithStorageImpl_BASE( rxContext ) 2281 , m_bStorageChanged( false ) 2282 { 2283 } 2284 2285 // ----------------------------------------------------------------------------- 2286 2287 StringResourceWithStorageImpl::~StringResourceWithStorageImpl() 2288 { 2289 } 2290 2291 // ----------------------------------------------------------------------------- 2292 // XServiceInfo 2293 // ----------------------------------------------------------------------------- 2294 2295 ::rtl::OUString StringResourceWithStorageImpl::getImplementationName( ) 2296 { 2297 return getImplementationName_StringResourceWithStorageImpl(); 2298 } 2299 2300 // ----------------------------------------------------------------------------- 2301 2302 sal_Bool StringResourceWithStorageImpl::supportsService( const ::rtl::OUString& rServiceName ) 2303 { 2304 Sequence< ::rtl::OUString > aNames( getSupportedServiceNames() ); 2305 const ::rtl::OUString* pNames = aNames.getConstArray(); 2306 const ::rtl::OUString* pEnd = pNames + aNames.getLength(); 2307 for ( ; pNames != pEnd && !pNames->equals( rServiceName ); ++pNames ) 2308 ; 2309 2310 return pNames != pEnd; 2311 } 2312 2313 // ----------------------------------------------------------------------------- 2314 2315 Sequence< ::rtl::OUString > StringResourceWithStorageImpl::getSupportedServiceNames( ) 2316 { 2317 return getSupportedServiceNames_StringResourceWithStorageImpl(); 2318 } 2319 2320 // ----------------------------------------------------------------------------- 2321 // XInitialization 2322 // ----------------------------------------------------------------------------- 2323 2324 void StringResourceWithStorageImpl::initialize( const Sequence< Any >& aArguments ) 2325 { 2326 ::osl::MutexGuard aGuard( getMutex() ); 2327 2328 if ( aArguments.getLength() != 5 ) 2329 { 2330 throw RuntimeException( 2331 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StringResourceWithStorageImpl::initialize: invalid number of arguments!" ) ), 2332 Reference< XInterface >() ); 2333 } 2334 2335 bool bOk = (aArguments[0] >>= m_xStorage); 2336 if( bOk && !m_xStorage.is() ) 2337 bOk = false; 2338 2339 if( !bOk ) 2340 { 2341 ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "StringResourceWithStorageImpl::initialize: invalid storage" ); 2342 throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 0 ); 2343 } 2344 2345 implInitializeCommonParameters( aArguments ); 2346 } 2347 2348 // ----------------------------------------------------------------------------- 2349 // Forwarding calls to base class 2350 2351 // XModifyBroadcaster 2352 void StringResourceWithStorageImpl::addModifyListener( const Reference< XModifyListener >& aListener ) 2353 { 2354 StringResourceImpl::addModifyListener( aListener ); 2355 } 2356 void StringResourceWithStorageImpl::removeModifyListener( const Reference< XModifyListener >& aListener ) 2357 { 2358 StringResourceImpl::removeModifyListener( aListener ); 2359 } 2360 2361 // XStringResourceResolver 2362 ::rtl::OUString StringResourceWithStorageImpl::resolveString( const ::rtl::OUString& ResourceID ) 2363 { 2364 return StringResourceImpl::resolveString( ResourceID ) ; 2365 } 2366 ::rtl::OUString StringResourceWithStorageImpl::resolveStringForLocale( const ::rtl::OUString& ResourceID, const Locale& locale ) 2367 { 2368 return StringResourceImpl::resolveStringForLocale( ResourceID, locale ); 2369 } 2370 sal_Bool StringResourceWithStorageImpl::hasEntryForId( const ::rtl::OUString& ResourceID ) 2371 { 2372 return StringResourceImpl::hasEntryForId( ResourceID ) ; 2373 } 2374 sal_Bool StringResourceWithStorageImpl::hasEntryForIdAndLocale( const ::rtl::OUString& ResourceID, 2375 const Locale& locale ) 2376 { 2377 return StringResourceImpl::hasEntryForIdAndLocale( ResourceID, locale ); 2378 } 2379 Sequence< ::rtl::OUString > StringResourceWithStorageImpl::getResourceIDs( ) 2380 { 2381 return StringResourceImpl::getResourceIDs(); 2382 } 2383 Sequence< ::rtl::OUString > StringResourceWithStorageImpl::getResourceIDsForLocale 2384 ( const Locale& locale ) 2385 { 2386 return StringResourceImpl::getResourceIDsForLocale( locale ); 2387 } 2388 Locale StringResourceWithStorageImpl::getCurrentLocale() 2389 { 2390 return StringResourceImpl::getCurrentLocale(); 2391 } 2392 Locale StringResourceWithStorageImpl::getDefaultLocale( ) 2393 { 2394 return StringResourceImpl::getDefaultLocale(); 2395 } 2396 Sequence< Locale > StringResourceWithStorageImpl::getLocales( ) 2397 { 2398 return StringResourceImpl::getLocales(); 2399 } 2400 2401 // XStringResourceManager 2402 sal_Bool StringResourceWithStorageImpl::isReadOnly() 2403 { 2404 return StringResourceImpl::isReadOnly(); 2405 } 2406 void StringResourceWithStorageImpl::setCurrentLocale( const Locale& locale, sal_Bool FindClosestMatch ) 2407 { 2408 StringResourceImpl::setCurrentLocale( locale, FindClosestMatch ); 2409 } 2410 void StringResourceWithStorageImpl::setDefaultLocale( const Locale& locale ) 2411 { 2412 StringResourceImpl::setDefaultLocale( locale ); 2413 } 2414 void StringResourceWithStorageImpl::setString( const ::rtl::OUString& ResourceID, const ::rtl::OUString& Str ) 2415 { 2416 StringResourceImpl::setString( ResourceID, Str ); 2417 } 2418 void StringResourceWithStorageImpl::setStringForLocale 2419 ( const ::rtl::OUString& ResourceID, const ::rtl::OUString& Str, const Locale& locale ) 2420 { 2421 StringResourceImpl::setStringForLocale( ResourceID, Str, locale ); 2422 } 2423 void StringResourceWithStorageImpl::removeId( const ::rtl::OUString& ResourceID ) 2424 { 2425 StringResourceImpl::removeId( ResourceID ); 2426 } 2427 void StringResourceWithStorageImpl::removeIdForLocale( const ::rtl::OUString& ResourceID, const Locale& locale ) 2428 { 2429 StringResourceImpl::removeIdForLocale( ResourceID, locale ); 2430 } 2431 void StringResourceWithStorageImpl::newLocale( const Locale& locale ) 2432 { 2433 StringResourceImpl::newLocale( locale ); 2434 } 2435 void StringResourceWithStorageImpl::removeLocale( const Locale& locale ) 2436 { 2437 StringResourceImpl::removeLocale( locale ); 2438 } 2439 sal_Int32 StringResourceWithStorageImpl::getUniqueNumericId( ) 2440 { 2441 return StringResourceImpl::getUniqueNumericId(); 2442 } 2443 2444 // XStringResourcePersistence 2445 void StringResourceWithStorageImpl::store() 2446 { 2447 ::osl::MutexGuard aGuard( getMutex() ); 2448 implCheckReadOnly( "StringResourceWithStorageImpl::store(): Read only" ); 2449 2450 bool bUsedForStore = true; 2451 bool bStoreAll = m_bStorageChanged; 2452 m_bStorageChanged = false; 2453 if( !m_bModified && !bStoreAll ) 2454 return; 2455 2456 implStoreAtStorage( m_aNameBase, m_aComment, m_xStorage, bUsedForStore, bStoreAll ); 2457 m_bModified = false; 2458 } 2459 2460 sal_Bool StringResourceWithStorageImpl::isModified( ) 2461 { 2462 return StringResourcePersistenceImpl::isModified(); 2463 } 2464 void StringResourceWithStorageImpl::setComment( const ::rtl::OUString& Comment ) 2465 { 2466 StringResourcePersistenceImpl::setComment( Comment ); 2467 } 2468 void StringResourceWithStorageImpl::storeToStorage( const Reference< XStorage >& Storage, 2469 const ::rtl::OUString& NameBase, const ::rtl::OUString& Comment ) 2470 { 2471 StringResourcePersistenceImpl::storeToStorage( Storage, NameBase, Comment ); 2472 } 2473 void StringResourceWithStorageImpl::storeToURL( const ::rtl::OUString& URL, 2474 const ::rtl::OUString& NameBase, const ::rtl::OUString& Comment, 2475 const Reference< ::com::sun::star::task::XInteractionHandler >& Handler ) 2476 { 2477 StringResourcePersistenceImpl::storeToURL( URL, NameBase, Comment, Handler ); 2478 } 2479 Sequence< ::sal_Int8 > StringResourceWithStorageImpl::exportBinary( ) 2480 { 2481 return StringResourcePersistenceImpl::exportBinary(); 2482 } 2483 void StringResourceWithStorageImpl::importBinary( const Sequence< ::sal_Int8 >& Data ) 2484 { 2485 StringResourcePersistenceImpl::importBinary( Data ); 2486 } 2487 2488 // ----------------------------------------------------------------------------- 2489 // XStringResourceWithStorage 2490 2491 void StringResourceWithStorageImpl::storeAsStorage( const Reference< XStorage >& Storage ) 2492 { 2493 setStorage( Storage ); 2494 store(); 2495 } 2496 2497 void StringResourceWithStorageImpl::setStorage( const Reference< XStorage >& Storage ) 2498 { 2499 ::osl::MutexGuard aGuard( getMutex() ); 2500 2501 if( !Storage.is() ) 2502 { 2503 ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii 2504 ( "StringResourceWithStorageImpl::setStorage: invalid storage" ); 2505 throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 0 ); 2506 } 2507 2508 implLoadAllLocales(); 2509 2510 m_xStorage = Storage; 2511 m_bStorageChanged = true; 2512 } 2513 2514 2515 // ============================================================================= 2516 // Private helper methods 2517 // ============================================================================= 2518 2519 // Scan locale properties files 2520 void StringResourceWithStorageImpl::implScanLocales( void ) 2521 { 2522 Reference< container::XNameAccess > xNameAccess( m_xStorage, UNO_QUERY ); 2523 if( xNameAccess.is() ) 2524 { 2525 Sequence< ::rtl::OUString > aContentSeq = xNameAccess->getElementNames(); 2526 implScanLocaleNames( aContentSeq ); 2527 } 2528 2529 implLoadAllLocales(); 2530 } 2531 2532 // Loading 2533 bool StringResourceWithStorageImpl::implLoadLocale( LocaleItem* pLocaleItem ) 2534 { 2535 bool bSuccess = false; 2536 try 2537 { 2538 ::rtl::OUString aStreamName = implGetFileNameForLocaleItem( pLocaleItem, m_aNameBase ); 2539 aStreamName += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(".properties") ); 2540 2541 Reference< io::XStream > xElementStream = 2542 m_xStorage->openStreamElement( aStreamName, ElementModes::READ ); 2543 2544 if( xElementStream.is() ) 2545 { 2546 Reference< io::XInputStream > xInputStream = xElementStream->getInputStream(); 2547 if( xInputStream.is() ) 2548 { 2549 bSuccess = StringResourcePersistenceImpl::implReadPropertiesFile( pLocaleItem, xInputStream ); 2550 xInputStream->closeInput(); 2551 } 2552 } 2553 } 2554 catch( uno::Exception& ) 2555 {} 2556 2557 return bSuccess; 2558 } 2559 2560 2561 // ============================================================================= 2562 // StringResourceWithLocationImpl 2563 // ============================================================================= 2564 2565 // component operations 2566 static Sequence< ::rtl::OUString > getSupportedServiceNames_StringResourceWithLocationImpl() 2567 { 2568 Sequence< ::rtl::OUString > names(1); 2569 names[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.resource.StringResourceWithLocation") ); 2570 return names; 2571 } 2572 2573 static ::rtl::OUString getImplementationName_StringResourceWithLocationImpl() 2574 { 2575 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.scripting.StringResourceWithLocation") ); 2576 } 2577 2578 static Reference< XInterface > SAL_CALL create_StringResourceWithLocationImpl( 2579 Reference< XComponentContext > const & xContext ) 2580 SAL_THROW( () ) 2581 { 2582 return static_cast< ::cppu::OWeakObject * >( new StringResourceWithLocationImpl( xContext ) ); 2583 } 2584 2585 // ----------------------------------------------------------------------------- 2586 2587 StringResourceWithLocationImpl::StringResourceWithLocationImpl( const Reference< XComponentContext >& rxContext ) 2588 : StringResourceWithLocationImpl_BASE( rxContext ) 2589 , m_bLocationChanged( false ) 2590 { 2591 } 2592 2593 // ----------------------------------------------------------------------------- 2594 2595 StringResourceWithLocationImpl::~StringResourceWithLocationImpl() 2596 { 2597 } 2598 2599 // ----------------------------------------------------------------------------- 2600 // XServiceInfo 2601 // ----------------------------------------------------------------------------- 2602 2603 ::rtl::OUString StringResourceWithLocationImpl::getImplementationName( ) 2604 { 2605 return getImplementationName_StringResourceWithLocationImpl(); 2606 } 2607 2608 // ----------------------------------------------------------------------------- 2609 2610 sal_Bool StringResourceWithLocationImpl::supportsService( const ::rtl::OUString& rServiceName ) 2611 { 2612 Sequence< ::rtl::OUString > aNames( getSupportedServiceNames() ); 2613 const ::rtl::OUString* pNames = aNames.getConstArray(); 2614 const ::rtl::OUString* pEnd = pNames + aNames.getLength(); 2615 for ( ; pNames != pEnd && !pNames->equals( rServiceName ); ++pNames ) 2616 ; 2617 2618 return pNames != pEnd; 2619 } 2620 2621 // ----------------------------------------------------------------------------- 2622 2623 Sequence< ::rtl::OUString > StringResourceWithLocationImpl::getSupportedServiceNames( ) 2624 { 2625 return getSupportedServiceNames_StringResourceWithLocationImpl(); 2626 } 2627 2628 // ----------------------------------------------------------------------------- 2629 // XInitialization 2630 // ----------------------------------------------------------------------------- 2631 2632 void StringResourceWithLocationImpl::initialize( const Sequence< Any >& aArguments ) 2633 { 2634 ::osl::MutexGuard aGuard( getMutex() ); 2635 2636 if ( aArguments.getLength() != 6 ) 2637 { 2638 throw RuntimeException( 2639 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM 2640 ( "XInitialization::initialize: invalid number of arguments!" ) ), 2641 Reference< XInterface >() ); 2642 } 2643 2644 bool bOk = (aArguments[0] >>= m_aLocation); 2645 sal_Int32 nLen = m_aLocation.getLength(); 2646 if( bOk && nLen == 0 ) 2647 { 2648 bOk = false; 2649 } 2650 else 2651 { 2652 if( m_aLocation.getStr()[nLen - 1] != '/' ) 2653 m_aLocation += ::rtl::OUString::createFromAscii( "/" ); 2654 } 2655 2656 if( !bOk ) 2657 { 2658 ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "XInitialization::initialize: invalid URL" ); 2659 throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 0 ); 2660 } 2661 2662 2663 bOk = (aArguments[5] >>= m_xInteractionHandler); 2664 if( !bOk ) 2665 { 2666 ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii( "StringResourceWithStorageImpl::initialize: invalid type" ); 2667 throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 5 ); 2668 } 2669 2670 implInitializeCommonParameters( aArguments ); 2671 } 2672 2673 // ----------------------------------------------------------------------------- 2674 // Forwarding calls to base class 2675 2676 // XModifyBroadcaster 2677 void StringResourceWithLocationImpl::addModifyListener( const Reference< XModifyListener >& aListener ) 2678 { 2679 StringResourceImpl::addModifyListener( aListener ); 2680 } 2681 void StringResourceWithLocationImpl::removeModifyListener( const Reference< XModifyListener >& aListener ) 2682 { 2683 StringResourceImpl::removeModifyListener( aListener ); 2684 } 2685 2686 // XStringResourceResolver 2687 ::rtl::OUString StringResourceWithLocationImpl::resolveString( const ::rtl::OUString& ResourceID ) 2688 { 2689 return StringResourceImpl::resolveString( ResourceID ) ; 2690 } 2691 ::rtl::OUString StringResourceWithLocationImpl::resolveStringForLocale( const ::rtl::OUString& ResourceID, const Locale& locale ) 2692 { 2693 return StringResourceImpl::resolveStringForLocale( ResourceID, locale ); 2694 } 2695 sal_Bool StringResourceWithLocationImpl::hasEntryForId( const ::rtl::OUString& ResourceID ) 2696 { 2697 return StringResourceImpl::hasEntryForId( ResourceID ) ; 2698 } 2699 sal_Bool StringResourceWithLocationImpl::hasEntryForIdAndLocale( const ::rtl::OUString& ResourceID, 2700 const Locale& locale ) 2701 { 2702 return StringResourceImpl::hasEntryForIdAndLocale( ResourceID, locale ); 2703 } 2704 Sequence< ::rtl::OUString > StringResourceWithLocationImpl::getResourceIDs( ) 2705 { 2706 return StringResourceImpl::getResourceIDs(); 2707 } 2708 Sequence< ::rtl::OUString > StringResourceWithLocationImpl::getResourceIDsForLocale 2709 ( const Locale& locale ) 2710 { 2711 return StringResourceImpl::getResourceIDsForLocale( locale ); 2712 } 2713 Locale StringResourceWithLocationImpl::getCurrentLocale() 2714 { 2715 return StringResourceImpl::getCurrentLocale(); 2716 } 2717 Locale StringResourceWithLocationImpl::getDefaultLocale( ) 2718 { 2719 return StringResourceImpl::getDefaultLocale(); 2720 } 2721 Sequence< Locale > StringResourceWithLocationImpl::getLocales( ) 2722 { 2723 return StringResourceImpl::getLocales(); 2724 } 2725 2726 // XStringResourceManager 2727 sal_Bool StringResourceWithLocationImpl::isReadOnly() 2728 { 2729 return StringResourceImpl::isReadOnly(); 2730 } 2731 void StringResourceWithLocationImpl::setCurrentLocale( const Locale& locale, sal_Bool FindClosestMatch ) 2732 { 2733 StringResourceImpl::setCurrentLocale( locale, FindClosestMatch ); 2734 } 2735 void StringResourceWithLocationImpl::setDefaultLocale( const Locale& locale ) 2736 { 2737 StringResourceImpl::setDefaultLocale( locale ); 2738 } 2739 void StringResourceWithLocationImpl::setString( const ::rtl::OUString& ResourceID, const ::rtl::OUString& Str ) 2740 { 2741 StringResourceImpl::setString( ResourceID, Str ); 2742 } 2743 void StringResourceWithLocationImpl::setStringForLocale 2744 ( const ::rtl::OUString& ResourceID, const ::rtl::OUString& Str, const Locale& locale ) 2745 { 2746 StringResourceImpl::setStringForLocale( ResourceID, Str, locale ); 2747 } 2748 void StringResourceWithLocationImpl::removeId( const ::rtl::OUString& ResourceID ) 2749 { 2750 StringResourceImpl::removeId( ResourceID ); 2751 } 2752 void StringResourceWithLocationImpl::removeIdForLocale( const ::rtl::OUString& ResourceID, const Locale& locale ) 2753 { 2754 StringResourceImpl::removeIdForLocale( ResourceID, locale ); 2755 } 2756 void StringResourceWithLocationImpl::newLocale( const Locale& locale ) 2757 { 2758 StringResourceImpl::newLocale( locale ); 2759 } 2760 void StringResourceWithLocationImpl::removeLocale( const Locale& locale ) 2761 { 2762 StringResourceImpl::removeLocale( locale ); 2763 } 2764 sal_Int32 StringResourceWithLocationImpl::getUniqueNumericId( ) 2765 { 2766 return StringResourceImpl::getUniqueNumericId(); 2767 } 2768 2769 // XStringResourcePersistence 2770 void StringResourceWithLocationImpl::store() 2771 { 2772 ::osl::MutexGuard aGuard( getMutex() ); 2773 implCheckReadOnly( "StringResourceWithLocationImpl::store(): Read only" ); 2774 2775 bool bUsedForStore = true; 2776 bool bStoreAll = m_bLocationChanged; 2777 m_bLocationChanged = false; 2778 if( !m_bModified && !bStoreAll ) 2779 return; 2780 2781 Reference< ucb::XSimpleFileAccess > xFileAccess = getFileAccess(); 2782 implStoreAtLocation( m_aLocation, m_aNameBase, m_aComment, 2783 xFileAccess, bUsedForStore, bStoreAll ); 2784 m_bModified = false; 2785 } 2786 2787 sal_Bool StringResourceWithLocationImpl::isModified( ) 2788 { 2789 return StringResourcePersistenceImpl::isModified(); 2790 } 2791 void StringResourceWithLocationImpl::setComment( const ::rtl::OUString& Comment ) 2792 { 2793 StringResourcePersistenceImpl::setComment( Comment ); 2794 } 2795 void StringResourceWithLocationImpl::storeToStorage( const Reference< XStorage >& Storage, 2796 const ::rtl::OUString& NameBase, const ::rtl::OUString& Comment ) 2797 { 2798 StringResourcePersistenceImpl::storeToStorage( Storage, NameBase, Comment ); 2799 } 2800 void StringResourceWithLocationImpl::storeToURL( const ::rtl::OUString& URL, 2801 const ::rtl::OUString& NameBase, const ::rtl::OUString& Comment, 2802 const Reference< ::com::sun::star::task::XInteractionHandler >& Handler ) 2803 { 2804 StringResourcePersistenceImpl::storeToURL( URL, NameBase, Comment, Handler ); 2805 } 2806 Sequence< ::sal_Int8 > StringResourceWithLocationImpl::exportBinary( ) 2807 { 2808 return StringResourcePersistenceImpl::exportBinary(); 2809 } 2810 void StringResourceWithLocationImpl::importBinary( const Sequence< ::sal_Int8 >& Data ) 2811 { 2812 StringResourcePersistenceImpl::importBinary( Data ); 2813 } 2814 2815 // ----------------------------------------------------------------------------- 2816 // XStringResourceWithLocation 2817 2818 // XStringResourceWithLocation 2819 void StringResourceWithLocationImpl::storeAsURL( const ::rtl::OUString& URL ) 2820 { 2821 setURL( URL ); 2822 store(); 2823 } 2824 2825 void StringResourceWithLocationImpl::setURL( const ::rtl::OUString& URL ) 2826 { 2827 ::osl::MutexGuard aGuard( getMutex() ); 2828 implCheckReadOnly( "StringResourceWithLocationImpl::setURL(): Read only" ); 2829 2830 sal_Int32 nLen = URL.getLength(); 2831 if( nLen == 0 ) 2832 { 2833 ::rtl::OUString errorMsg = ::rtl::OUString::createFromAscii 2834 ( "StringResourceWithLocationImpl::setURL: invalid URL" ); 2835 throw IllegalArgumentException( errorMsg, Reference< XInterface >(), 0 ); 2836 } 2837 2838 implLoadAllLocales(); 2839 2840 // Delete files at old location 2841 bool bUsedForStore = false; 2842 bool bStoreAll = false; 2843 bool bKillAll = true; 2844 implStoreAtLocation( m_aLocation, m_aNameBase, m_aComment, 2845 getFileAccess(), bUsedForStore, bStoreAll, bKillAll ); 2846 2847 m_aLocation = URL; 2848 m_bLocationChanged = true; 2849 } 2850 2851 2852 // ============================================================================= 2853 // Private helper methods 2854 // ============================================================================= 2855 2856 // Scan locale properties files 2857 void StringResourceWithLocationImpl::implScanLocales( void ) 2858 { 2859 const Reference< ucb::XSimpleFileAccess > xFileAccess = getFileAccess(); 2860 if( xFileAccess.is() && xFileAccess->isFolder( m_aLocation ) ) 2861 { 2862 Sequence< ::rtl::OUString > aContentSeq = xFileAccess->getFolderContents( m_aLocation, false ); 2863 implScanLocaleNames( aContentSeq ); 2864 } 2865 } 2866 2867 // Loading 2868 bool StringResourceWithLocationImpl::implLoadLocale( LocaleItem* pLocaleItem ) 2869 { 2870 bool bSuccess = false; 2871 2872 const Reference< ucb::XSimpleFileAccess > xFileAccess = getFileAccess(); 2873 if( xFileAccess.is() ) 2874 { 2875 ::rtl::OUString aCompleteFileName = 2876 implGetPathForLocaleItem( pLocaleItem, m_aNameBase, m_aLocation ); 2877 2878 Reference< io::XInputStream > xInputStream; 2879 try 2880 { 2881 xInputStream = xFileAccess->openFileRead( aCompleteFileName ); 2882 } 2883 catch( Exception& ) 2884 {} 2885 if( xInputStream.is() ) 2886 { 2887 bSuccess = StringResourcePersistenceImpl::implReadPropertiesFile( pLocaleItem, xInputStream ); 2888 xInputStream->closeInput(); 2889 } 2890 } 2891 2892 return bSuccess; 2893 } 2894 2895 const Reference< ucb::XSimpleFileAccess > StringResourceWithLocationImpl::getFileAccess( void ) 2896 { 2897 ::osl::MutexGuard aGuard( getMutex() ); 2898 2899 if( !m_xSFI.is() ) 2900 { 2901 Reference< XMultiComponentFactory > xMCF = getMultiComponentFactory(); 2902 m_xSFI = Reference< ucb::XSimpleFileAccess >( xMCF->createInstanceWithContext 2903 ( ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ), m_xContext ), UNO_QUERY ); 2904 2905 if( m_xSFI.is() && m_xInteractionHandler.is() ) 2906 m_xSFI->setInteractionHandler( m_xInteractionHandler ); 2907 } 2908 return m_xSFI; 2909 } 2910 2911 2912 // ============================================================================= 2913 // component export operations 2914 // ============================================================================= 2915 2916 static struct ::cppu::ImplementationEntry s_component_entries [] = 2917 { 2918 { 2919 create_StringResourceImpl, getImplementationName_StringResourceImpl, 2920 getSupportedServiceNames_StringResourceImpl, 2921 ::cppu::createSingleComponentFactory, 2922 0, 0 2923 }, 2924 { 2925 create_StringResourceWithLocationImpl, getImplementationName_StringResourceWithLocationImpl, 2926 getSupportedServiceNames_StringResourceWithLocationImpl, 2927 ::cppu::createSingleComponentFactory, 2928 0, 0 2929 }, 2930 { 2931 create_StringResourceWithStorageImpl, getImplementationName_StringResourceWithStorageImpl, 2932 getSupportedServiceNames_StringResourceWithStorageImpl, 2933 ::cppu::createSingleComponentFactory, 2934 0, 0 2935 }, 2936 { 0, 0, 0, 0, 0, 0 } 2937 }; 2938 2939 2940 //......................................................................... 2941 } // namespace dlgprov 2942 //......................................................................... 2943 2944 2945 // ============================================================================= 2946 // component exports 2947 // ============================================================================= 2948 2949 extern "C" 2950 { 2951 void SAL_CALL component_getImplementationEnvironment( 2952 const sal_Char ** ppEnvTypeName, uno_Environment ** ppEnv ) 2953 { 2954 (void)ppEnv; 2955 2956 *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; 2957 } 2958 2959 void * SAL_CALL component_getFactory( 2960 const sal_Char * pImplName, lang::XMultiServiceFactory * pServiceManager, 2961 registry::XRegistryKey * pRegistryKey ) 2962 { 2963 return ::cppu::component_getFactoryHelper( 2964 pImplName, pServiceManager, pRegistryKey, ::stringresource::s_component_entries ); 2965 } 2966 } 2967