1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_tools.hxx" 30 31 #include <string.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <vos/signal.hxx> 35 #include <tools/debug.hxx> 36 #ifndef _TABLE_HXX 37 #include <tools/table.hxx> 38 #endif 39 #include <tools/stream.hxx> 40 #include <tools/resmgr.hxx> 41 #include <tools/rc.hxx> 42 #include <tools/rcid.h> 43 #include <osl/endian.h> 44 #include <osl/process.h> 45 #include <osl/thread.h> 46 #include <osl/file.hxx> 47 #include <osl/mutex.hxx> 48 #include <rtl/ustrbuf.hxx> 49 #include <rtl/strbuf.hxx> 50 #include <tools/urlobj.hxx> 51 #include <rtl/instance.hxx> 52 #include <rtl/bootstrap.hxx> 53 #include <i18npool/mslangid.hxx> 54 #include <tools/simplerm.hxx> 55 56 #include <tools/isofallback.hxx> 57 58 #include <functional> 59 #include <algorithm> 60 #include <hash_map> 61 #include <list> 62 #include <set> 63 64 #ifdef UNX 65 #define SEARCH_PATH_DELIMITER_CHAR_STRING ":" 66 #define SEARCH_PATH_DELIMITER ':' 67 #else 68 #define SEARCH_PATH_DELIMITER_CHAR_STRING ";" 69 #define SEARCH_PATH_DELIMITER ';' 70 #endif 71 72 #define SEARCH_PATH_DELIMITER_STRING ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SEARCH_PATH_DELIMITER_CHAR_STRING ) ) 73 74 using namespace rtl; 75 using namespace osl; 76 77 // for thread safety 78 static osl::Mutex* pResMgrMutex = NULL; 79 static osl::Mutex& getResMgrMutex() 80 { 81 if( !pResMgrMutex ) 82 { 83 osl::Guard<osl::Mutex> aGuard( *osl::Mutex::getGlobalMutex() ); 84 if( ! pResMgrMutex ) 85 pResMgrMutex = new osl::Mutex(); 86 } 87 return *pResMgrMutex; 88 } 89 90 struct ImpContent; 91 class InternalResMgr 92 { 93 friend class ResMgr; 94 friend class SimpleResMgr; 95 friend class ResMgrContainer; 96 97 ImpContent * pContent; 98 sal_uInt32 nOffCorrection; 99 sal_uInt8 * pStringBlock; 100 SvStream * pStm; 101 sal_Bool bEqual2Content; 102 sal_uInt32 nEntries; 103 OUString aFileName; 104 OUString aPrefix; 105 OUString aResName; 106 bool bSingular; 107 com::sun::star::lang::Locale aLocale; 108 std::hash_map<sal_uInt64, int>* pResUseDump; 109 110 InternalResMgr( const OUString& rFileURL, 111 const OUString& aPrefix, 112 const OUString& aResName, 113 const com::sun::star::lang::Locale& rLocale ); 114 ~InternalResMgr(); 115 sal_Bool Create(); 116 117 sal_Bool IsGlobalAvailable( RESOURCE_TYPE nRT, sal_uInt32 nId ) const; 118 void * LoadGlobalRes( RESOURCE_TYPE nRT, sal_uInt32 nId, 119 void **pResHandle ); 120 public: 121 void FreeGlobalRes( void *, void * ); 122 123 SvStream * GetBitmapStream( sal_uInt32 nResId ); 124 }; 125 126 // ======================================================================= 127 128 class ResMgrContainer 129 { 130 static ResMgrContainer* pOneInstance; 131 132 struct ContainerElement 133 { 134 InternalResMgr* pResMgr; 135 OUString aFileURL; 136 int nRefCount; 137 int nLoadCount; 138 139 ContainerElement() : 140 pResMgr( NULL ), 141 nRefCount( 0 ), 142 nLoadCount( 0 ) 143 {} 144 }; 145 146 std::hash_map< OUString, ContainerElement, OUStringHash> m_aResFiles; 147 com::sun::star::lang::Locale m_aDefLocale; 148 149 ResMgrContainer() { init(); } 150 ~ResMgrContainer(); 151 152 void init(); 153 public: 154 155 static ResMgrContainer& get(); 156 static void release(); 157 158 InternalResMgr* getResMgr( const OUString& rPrefix, 159 com::sun::star::lang::Locale& rLocale, 160 bool bForceNewInstance = false 161 ); 162 InternalResMgr* getNextFallback( InternalResMgr* pResMgr ); 163 164 void freeResMgr( InternalResMgr* pResMgr ); 165 166 void setDefLocale( const com::sun::star::lang::Locale& rLocale ) 167 { m_aDefLocale = rLocale; } 168 const com::sun::star::lang::Locale& getDefLocale() const 169 { return m_aDefLocale; } 170 }; 171 172 ResMgrContainer* ResMgrContainer::pOneInstance = NULL; 173 174 ResMgrContainer& ResMgrContainer::get() 175 { 176 if( ! pOneInstance ) 177 pOneInstance = new ResMgrContainer(); 178 return *pOneInstance; 179 } 180 181 ResMgrContainer::~ResMgrContainer() 182 { 183 for( std::hash_map< OUString, ContainerElement, OUStringHash >::iterator it = 184 m_aResFiles.begin(); it != m_aResFiles.end(); ++it ) 185 { 186 OSL_TRACE( "Resource file %s loaded %d times\n", 187 OUStringToOString( it->second.aFileURL, osl_getThreadTextEncoding() ).getStr(), 188 it->second.nLoadCount ); 189 delete it->second.pResMgr; 190 } 191 } 192 193 void ResMgrContainer::release() 194 { 195 delete pOneInstance; 196 pOneInstance = NULL; 197 } 198 199 void ResMgrContainer::init() 200 { 201 // get resource path 202 std::list< OUString > aDirs; 203 sal_Int32 nIndex = 0; 204 205 // 1. fixed locations 206 rtl::OUString uri( 207 RTL_CONSTASCII_USTRINGPARAM("$BRAND_BASE_DIR/program/resource")); 208 rtl::Bootstrap::expandMacros(uri); 209 aDirs.push_back(uri); 210 uri = rtl::OUString( 211 RTL_CONSTASCII_USTRINGPARAM("$OOO_BASE_DIR/program/resource")); 212 rtl::Bootstrap::expandMacros(uri); 213 aDirs.push_back(uri); 214 215 // 2. in STAR_RESOURCEPATH 216 const sal_Char* pEnv = getenv( "STAR_RESOURCEPATH" ); 217 if( pEnv ) 218 { 219 OUString aEnvPath( OStringToOUString( OString( pEnv ), osl_getThreadTextEncoding() ) ); 220 nIndex = 0; 221 while( nIndex >= 0 ) 222 { 223 OUString aPathElement( aEnvPath.getToken( 0, SEARCH_PATH_DELIMITER, nIndex ) ); 224 if( aPathElement.getLength() ) 225 { 226 OUString aFileURL; 227 File::getFileURLFromSystemPath( aPathElement, aFileURL ); 228 aDirs.push_back( aFileURL); 229 } 230 } 231 } 232 233 // collect all possible resource files 234 for( std::list< OUString >::const_iterator dir_it = aDirs.begin(); dir_it != aDirs.end(); ++dir_it ) 235 { 236 Directory aDir( *dir_it ); 237 if( aDir.open() == FileBase::E_None ) 238 { 239 DirectoryItem aItem; 240 while( aDir.getNextItem( aItem ) == FileBase::E_None ) 241 { 242 FileStatus aStatus(FileStatusMask_FileName); 243 if( aItem.getFileStatus( aStatus ) == FileBase::E_None ) 244 { 245 OUString aFileName = aStatus.getFileName(); 246 if( aFileName.getLength() < 5 ) 247 continue; 248 if( ! aFileName.endsWithIgnoreAsciiCaseAsciiL( ".res", 4 ) ) 249 continue; 250 OUString aResName = aFileName.copy( 0, aFileName.getLength()-4 ); 251 if( m_aResFiles.find( aResName ) != m_aResFiles.end() ) 252 continue; 253 OUStringBuffer aURL( dir_it->getLength() + aFileName.getLength() + 1 ); 254 aURL.append( *dir_it ); 255 if( !dir_it->endsWithIgnoreAsciiCaseAsciiL( "/", 1 ) ) 256 aURL.append( sal_Unicode('/') ); 257 aURL.append( aFileName ); 258 m_aResFiles[ aResName ].aFileURL = aURL.makeStringAndClear(); 259 } 260 } 261 } 262 #if OSL_DEBUG_LEVEL > 1 263 else 264 OSL_TRACE( "opening dir %s failed\n", OUStringToOString( *dir_it, osl_getThreadTextEncoding() ).getStr() ); 265 #endif 266 } 267 #if OSL_DEBUG_LEVEL > 1 268 for( std::hash_map< OUString, ContainerElement, OUStringHash >::const_iterator it = 269 m_aResFiles.begin(); it != m_aResFiles.end(); ++it ) 270 { 271 OSL_TRACE( "ResMgrContainer: %s -> %s\n", 272 OUStringToOString( it->first, osl_getThreadTextEncoding() ).getStr(), 273 OUStringToOString( it->second.aFileURL, osl_getThreadTextEncoding() ).getStr() ); 274 } 275 #endif 276 277 // set default language 278 LanguageType nLang = MsLangId::getSystemUILanguage(); 279 MsLangId::convertLanguageToLocale(nLang, m_aDefLocale); 280 } 281 282 InternalResMgr* ResMgrContainer::getResMgr( const OUString& rPrefix, 283 com::sun::star::lang::Locale& rLocale, 284 bool bForceNewInstance 285 ) 286 { 287 com::sun::star::lang::Locale aLocale( rLocale ); 288 OUStringBuffer aSearch( rPrefix.getLength() + 16 ); 289 std::hash_map< OUString, ContainerElement, OUStringHash >::iterator it = m_aResFiles.end(); 290 291 int nTries = 0; 292 if( aLocale.Language.getLength() > 0 ) 293 nTries = 1; 294 if( aLocale.Country.getLength() > 0 ) 295 nTries = 2; 296 if( aLocale.Variant.getLength() > 0 ) 297 nTries = 3; 298 while( nTries-- ) 299 { 300 aSearch.append( rPrefix ); 301 if( nTries > -1 ) 302 { 303 aSearch.append( aLocale.Language ); 304 } 305 if( nTries > 0 ) 306 { 307 aSearch.append( sal_Unicode('-') ); 308 aSearch.append( aLocale.Country ); 309 } 310 if( nTries > 1 ) 311 { 312 aSearch.append( sal_Unicode('-') ); 313 aSearch.append( aLocale.Variant ); 314 } 315 it = m_aResFiles.find( aSearch.makeStringAndClear() ); 316 if( it != m_aResFiles.end() ) 317 { 318 // ensure InternalResMgr existance 319 if( ! it->second.pResMgr ) 320 { 321 InternalResMgr* pImp = 322 new InternalResMgr( it->second.aFileURL, rPrefix, it->first, aLocale ); 323 if( ! pImp->Create() ) 324 { 325 delete pImp; 326 continue; 327 } 328 it->second.pResMgr = pImp; 329 } 330 break; 331 } 332 if( nTries == 0 && !aLocale.Language.equalsIgnoreAsciiCaseAscii( "en" ) ) 333 { 334 // locale fallback failed 335 // fallback to en-US locale 336 nTries = 2; 337 aLocale.Language = OUString( RTL_CONSTASCII_USTRINGPARAM( "en" ) ); 338 aLocale.Country = OUString( RTL_CONSTASCII_USTRINGPARAM( "US" ) ); 339 aLocale.Variant = OUString(); 340 } 341 } 342 // try if there is anything with this prefix at all 343 if( it == m_aResFiles.end() ) 344 { 345 aLocale = com::sun::star::lang::Locale(); 346 it = m_aResFiles.find( rPrefix ); 347 if( it == m_aResFiles.end() ) 348 { 349 for( it = m_aResFiles.begin(); it != m_aResFiles.end(); ++it ) 350 { 351 if( it->first.matchIgnoreAsciiCase( rPrefix ) ) 352 { 353 // ensure InternalResMgr existance 354 if( ! it->second.pResMgr ) 355 { 356 InternalResMgr* pImp = 357 new InternalResMgr( it->second.aFileURL, 358 rPrefix, 359 it->first, 360 aLocale ); 361 if( ! pImp->Create() ) 362 { 363 delete pImp; 364 continue; 365 } 366 it->second.pResMgr = pImp; 367 } 368 // try to guess locale 369 sal_Int32 nIndex = rPrefix.getLength(); 370 aLocale.Language = it->first.getToken( 0, '-', nIndex ); 371 if( nIndex > 0 ) 372 aLocale.Country = it->first.getToken( 0, '-', nIndex ); 373 if( nIndex > 0 ) 374 aLocale.Variant = it->first.getToken( 0, '-', nIndex ); 375 break; 376 } 377 } 378 } 379 } 380 // give up 381 if( it == m_aResFiles.end() ) 382 { 383 OUStringBuffer sKey = rPrefix; 384 sKey.append( rLocale.Language ); 385 if( rLocale.Country.getLength() ) 386 { 387 sKey.append( sal_Unicode('-') ); 388 sKey.append( rLocale.Country ); 389 } 390 if( rLocale.Variant.getLength() ) 391 { 392 sKey.append( sal_Unicode('-') ); 393 sKey.append( rLocale.Variant ); 394 } // if( aLocale.Variant.getLength() ) 395 ::rtl::OUString sURL = sKey.makeStringAndClear(); 396 sURL += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".res")); 397 if ( m_aResFiles.find(sURL) == m_aResFiles.end() ) 398 { 399 m_aResFiles[ sURL ].aFileURL = sURL; 400 return getResMgr(rPrefix,rLocale,bForceNewInstance); 401 } // if ( m_aResFiles.find(sURL) == m_aResFiles.end() ) 402 return NULL; 403 } 404 405 rLocale = aLocale; 406 // at this point it->second.pResMgr must be filled either by creating a new one 407 // (then the refcount is still 0) or because we already had one 408 InternalResMgr* pImp = it->second.pResMgr; 409 410 if( it->second.nRefCount == 0 ) 411 it->second.nLoadCount++; 412 413 // for SimpleResMgr 414 if( bForceNewInstance ) 415 { 416 if( it->second.nRefCount == 0 ) 417 { 418 // shortcut: the match algorithm already created the InternalResMgr 419 // take it instead of creating yet another one 420 it->second.pResMgr = NULL; 421 pImp->bSingular = true; 422 } 423 else 424 { 425 pImp = new InternalResMgr( it->second.aFileURL, rPrefix, it->first, aLocale ); 426 pImp->bSingular = true; 427 if( !pImp->Create() ) 428 { 429 delete pImp; 430 pImp = NULL; 431 } 432 else 433 it->second.nLoadCount++; 434 } 435 } 436 else 437 it->second.nRefCount++; 438 439 return pImp; 440 } 441 442 InternalResMgr* ResMgrContainer::getNextFallback( InternalResMgr* pMgr ) 443 { 444 com::sun::star::lang::Locale aLocale = pMgr->aLocale; 445 if( aLocale.Variant.getLength() ) 446 aLocale.Variant = OUString(); 447 else if( aLocale.Country.getLength() ) 448 aLocale.Country = OUString(); 449 else if( ! aLocale.Language.equalsIgnoreAsciiCaseAscii( "en" ) ) 450 { 451 aLocale.Language = OUString( RTL_CONSTASCII_USTRINGPARAM( "en" ) ); 452 aLocale.Country = OUString( RTL_CONSTASCII_USTRINGPARAM( "US" ) ); 453 } 454 InternalResMgr* pNext = getResMgr( pMgr->aPrefix, aLocale, pMgr->bSingular ); 455 // prevent recursion 456 if( pNext == pMgr || pNext->aResName.equals( pMgr->aResName ) ) 457 { 458 if( pNext->bSingular ) 459 delete pNext; 460 pNext = NULL; 461 } 462 return pNext; 463 } 464 465 void ResMgrContainer::freeResMgr( InternalResMgr* pResMgr ) 466 { 467 if( pResMgr->bSingular ) 468 delete pResMgr; 469 else 470 { 471 std::hash_map< OUString, ContainerElement, OUStringHash >::iterator it = 472 m_aResFiles.find( pResMgr->aResName ); 473 if( it != m_aResFiles.end() ) 474 { 475 DBG_ASSERT( it->second.nRefCount > 0, "InternalResMgr freed too often" ); 476 if( it->second.nRefCount > 0 ) 477 it->second.nRefCount--; 478 if( it->second.nRefCount == 0 ) 479 { 480 delete it->second.pResMgr; 481 it->second.pResMgr = NULL; 482 } 483 } 484 } 485 } 486 487 // ======================================================================= 488 489 void Resource::TestRes() 490 { 491 if( m_pResMgr ) 492 m_pResMgr->TestStack( this ); 493 } 494 495 struct ImpContent 496 { 497 sal_uInt64 nTypeAndId; 498 sal_uInt32 nOffset; 499 }; 500 501 struct ImpContentLessCompare : public ::std::binary_function< ImpContent, ImpContent, bool> 502 { 503 inline bool operator() (const ImpContent& lhs, const ImpContent& rhs) const 504 { 505 return lhs.nTypeAndId < rhs.nTypeAndId; 506 } 507 }; 508 509 struct ImpContentMixLessCompare : public ::std::binary_function< ImpContent, sal_uInt64, bool> 510 { 511 inline bool operator() (const ImpContent& lhs, const sal_uInt64& rhs) const 512 { 513 return lhs.nTypeAndId < rhs; 514 } 515 inline bool operator() (const sal_uInt64& lhs, const ImpContent& rhs) const 516 { 517 return lhs < rhs.nTypeAndId; 518 } 519 }; 520 521 522 // ======================================================================= 523 524 static ResHookProc pImplResHookProc = 0; 525 526 // ======================================================================= 527 528 SvStream * InternalResMgr::GetBitmapStream( sal_uInt32 nId ) 529 { 530 // Anfang der Strings suchen 531 ImpContent * pFind = ::std::lower_bound(pContent, 532 pContent + nEntries, 533 ((sal_uInt64(RT_SYS_BITMAP) << 32) | nId), 534 ImpContentMixLessCompare()); 535 if ( (pFind != (pContent + nEntries)) && (pFind->nTypeAndId == ((sal_uInt64(RT_SYS_BITMAP) << 32) | nId)) ) 536 { 537 pStm->Seek( pFind->nOffset ); 538 return pStm; 539 } 540 return NULL; 541 } 542 543 // ----------------------------------------------------------------------- 544 545 InternalResMgr::InternalResMgr( const OUString& rFileURL, 546 const OUString& rPrefix, 547 const OUString& rResName, 548 const com::sun::star::lang::Locale& rLocale ) 549 : pContent( NULL ) 550 , pStringBlock( NULL ) 551 , pStm( NULL ) 552 , bEqual2Content( sal_True ) 553 , nEntries( 0 ) 554 , aFileName( rFileURL ) 555 , aPrefix( rPrefix ) 556 , aResName( rResName ) 557 , bSingular( false ) 558 , aLocale( rLocale ) 559 , pResUseDump( 0 ) 560 { 561 } 562 563 // ----------------------------------------------------------------------- 564 565 InternalResMgr::~InternalResMgr() 566 { 567 rtl_freeMemory(pContent); 568 rtl_freeMemory(pStringBlock); 569 delete pStm; 570 571 #ifdef DBG_UTIL 572 if( pResUseDump ) 573 { 574 const sal_Char* pLogFile = getenv( "STAR_RESOURCE_LOGGING" ); 575 if ( pLogFile ) 576 { 577 SvFileStream aStm( UniString( pLogFile, RTL_TEXTENCODING_ASCII_US ), STREAM_WRITE ); 578 aStm.Seek( STREAM_SEEK_TO_END ); 579 ByteString aLine( "FileName: " ); 580 aLine.Append( ByteString( OUStringToOString( aFileName, RTL_TEXTENCODING_UTF8 ) ) ); 581 aStm.WriteLine( aLine ); 582 583 for( std::hash_map<sal_uInt64, int>::const_iterator it = pResUseDump->begin(); 584 it != pResUseDump->end(); ++it ) 585 { 586 sal_uInt64 nKeyId = it->first; 587 aLine.Assign( "Type/Id: " ); 588 aLine.Append( ByteString::CreateFromInt32( sal::static_int_cast< sal_Int32 >((nKeyId >> 32) & 0xFFFFFFFF) ) ); 589 aLine.Append( '/' ); 590 aLine.Append( ByteString::CreateFromInt32( sal::static_int_cast< sal_Int32 >(nKeyId & 0xFFFFFFFF) ) ); 591 aStm.WriteLine( aLine ); 592 } 593 } 594 } 595 #endif 596 597 delete pResUseDump; 598 } 599 600 // ----------------------------------------------------------------------- 601 602 603 sal_Bool InternalResMgr::Create() 604 { 605 ResMgrContainer::get(); 606 sal_Bool bDone = sal_False; 607 608 pStm = new SvFileStream( aFileName, (STREAM_READ | STREAM_SHARE_DENYWRITE | STREAM_NOCREATE) ); 609 if( pStm->GetError() == 0 ) 610 { 611 sal_Int32 lContLen = 0; 612 613 pStm->Seek( STREAM_SEEK_TO_END ); 614 /* 615 if( ( pInternalResMgr->pHead = (RSHEADER_TYPE *)mmap( 0, nResourceFileSize, 616 PROT_READ, MAP_PRIVATE, 617 fRes, 0 ) ) != (RSHEADER_TYPE *)-1) 618 */ 619 pStm->SeekRel( - (int)sizeof( lContLen ) ); 620 pStm->Read( &lContLen, sizeof( lContLen ) ); 621 // is bigendian, swab to the right endian 622 lContLen = ResMgr::GetLong( &lContLen ); 623 pStm->SeekRel( -lContLen ); 624 // allocate stored ImpContent data (12 bytes per unit) 625 sal_uInt8* pContentBuf = (sal_uInt8*)rtl_allocateMemory( lContLen ); 626 pStm->Read( pContentBuf, lContLen ); 627 // allocate ImpContent space (sizeof(ImpContent) per unit, not necessarily 12) 628 pContent = (ImpContent *)rtl_allocateMemory( sizeof(ImpContent)*lContLen/12 ); 629 // Auf die Anzahl der ImpContent k�rzen 630 nEntries = (sal_uInt32)lContLen / 12; 631 bEqual2Content = sal_True; // Die Daten der Resourcen liegen 632 // genauso wie das Inhaltsverzeichnis 633 sal_Bool bSorted = sal_True; 634 if( nEntries ) 635 { 636 #ifdef DBG_UTIL 637 const sal_Char* pLogFile = getenv( "STAR_RESOURCE_LOGGING" ); 638 if ( pLogFile ) 639 { 640 pResUseDump = new std::hash_map<sal_uInt64, int>; 641 for( sal_uInt32 i = 0; i < nEntries; ++i ) 642 (*pResUseDump)[pContent[i].nTypeAndId] = 1; 643 } 644 #endif 645 // swap the content to the right endian 646 pContent[0].nTypeAndId = ResMgr::GetUInt64( pContentBuf ); 647 pContent[0].nOffset = ResMgr::GetLong( pContentBuf+8 ); 648 sal_uInt32 nCount = nEntries - 1; 649 for( sal_uInt32 i = 0,j=1; i < nCount; ++i,++j ) 650 { 651 // swap the content to the right endian 652 pContent[j].nTypeAndId = ResMgr::GetUInt64( pContentBuf + (12*j) ); 653 pContent[j].nOffset = ResMgr::GetLong( pContentBuf + (12*j+8) ); 654 if( pContent[i].nTypeAndId >= pContent[j].nTypeAndId ) 655 bSorted = sal_False; 656 if( (pContent[i].nTypeAndId & 0xFFFFFFFF00000000LL) == (pContent[j].nTypeAndId & 0xFFFFFFFF00000000LL) 657 && pContent[i].nOffset >= pContent[j].nOffset ) 658 bEqual2Content = sal_False; 659 } 660 } 661 rtl_freeMemory( pContentBuf ); 662 #ifndef OS2 663 OSL_ENSURE( bSorted, "content not sorted" ); 664 #endif 665 OSL_ENSURE( bEqual2Content, "resource structure wrong" ); 666 if( !bSorted ) 667 ::std::sort(pContent,pContent+nEntries,ImpContentLessCompare()); 668 // qsort( pContent, nEntries, sizeof( ImpContent ), Compare ); 669 670 bDone = sal_True; 671 } 672 673 return bDone; 674 } 675 676 // ----------------------------------------------------------------------- 677 678 sal_Bool InternalResMgr::IsGlobalAvailable( RESOURCE_TYPE nRT, sal_uInt32 nId ) const 679 { 680 // Anfang der Strings suchen 681 sal_uInt64 nValue = ((sal_uInt64(nRT) << 32) | nId); 682 ImpContent * pFind = ::std::lower_bound(pContent, 683 pContent + nEntries, 684 nValue, 685 ImpContentMixLessCompare()); 686 return (pFind != (pContent + nEntries)) && (pFind->nTypeAndId == nValue); 687 } 688 689 // ----------------------------------------------------------------------- 690 691 void* InternalResMgr::LoadGlobalRes( RESOURCE_TYPE nRT, sal_uInt32 nId, 692 void **pResHandle ) 693 { 694 #ifdef DBG_UTIL 695 if( pResUseDump ) 696 pResUseDump->erase( (sal_uInt64(nRT) << 32) | nId ); 697 #endif 698 // Anfang der Strings suchen 699 sal_uInt64 nValue = ((sal_uInt64(nRT) << 32) | nId); 700 ImpContent* pEnd = (pContent + nEntries); 701 ImpContent* pFind = ::std::lower_bound( pContent, 702 pEnd, 703 nValue, 704 ImpContentMixLessCompare()); 705 if( pFind && (pFind != pEnd) && (pFind->nTypeAndId == nValue) ) 706 { 707 if( nRT == RSC_STRING && bEqual2Content ) 708 { 709 // String Optimierung 710 if( !pStringBlock ) 711 { 712 // Anfang der Strings suchen 713 ImpContent * pFirst = pFind; 714 ImpContent * pLast = pFirst; 715 while( pFirst > pContent && ((pFirst -1)->nTypeAndId >> 32) == RSC_STRING ) 716 --pFirst; 717 while( pLast < pEnd && (pLast->nTypeAndId >> 32) == RSC_STRING ) 718 ++pLast; 719 nOffCorrection = pFirst->nOffset; 720 sal_uInt32 nSize; 721 --pLast; 722 pStm->Seek( pLast->nOffset ); 723 RSHEADER_TYPE aHdr; 724 pStm->Read( &aHdr, sizeof( aHdr ) ); 725 nSize = pLast->nOffset + aHdr.GetGlobOff() - nOffCorrection; 726 pStringBlock = (sal_uInt8*)rtl_allocateMemory( nSize ); 727 pStm->Seek( pFirst->nOffset ); 728 pStm->Read( pStringBlock, nSize ); 729 } 730 *pResHandle = pStringBlock; 731 return (sal_uInt8*)pStringBlock + pFind->nOffset - nOffCorrection; 732 } // if( nRT == RSC_STRING && bEqual2Content ) 733 else 734 { 735 *pResHandle = 0; 736 RSHEADER_TYPE aHeader; 737 pStm->Seek( pFind->nOffset ); 738 pStm->Read( &aHeader, sizeof( RSHEADER_TYPE ) ); 739 void * pRes = rtl_allocateMemory( aHeader.GetGlobOff() ); 740 memcpy( pRes, &aHeader, sizeof( RSHEADER_TYPE ) ); 741 pStm->Read( (sal_uInt8*)pRes + sizeof( RSHEADER_TYPE ), 742 aHeader.GetGlobOff() - sizeof( RSHEADER_TYPE ) ); 743 return pRes; 744 } 745 } // if( pFind && (pFind != pEnd) && (pFind->nTypeAndId == nValue) ) 746 *pResHandle = 0; 747 //Resource holen 748 return NULL; 749 } 750 751 // ----------------------------------------------------------------------- 752 753 void InternalResMgr::FreeGlobalRes( void * pResHandle, void * pResource ) 754 { 755 if ( !pResHandle ) 756 // REsource wurde extra allokiert 757 rtl_freeMemory(pResource); 758 } 759 760 // ======================================================================= 761 762 #ifdef DBG_UTIL 763 764 UniString GetTypeRes_Impl( const ResId& rTypeId ) 765 { 766 // Funktion verlassen, falls Resourcefehler in dieser Funktion 767 static int bInUse = sal_False; 768 UniString aTypStr( UniString::CreateFromInt32( rTypeId.GetId() ) ); 769 770 if ( !bInUse ) 771 { 772 bInUse = sal_True; 773 774 ResId aResId( sal_uInt32(RSCVERSION_ID), *rTypeId.GetResMgr() ); 775 aResId.SetRT( RSC_VERSIONCONTROL ); 776 777 if ( rTypeId.GetResMgr()->GetResource( aResId ) ) 778 { 779 rTypeId.SetRT( RSC_STRING ); 780 if ( rTypeId.GetResMgr()->IsAvailable( rTypeId ) ) 781 { 782 aTypStr = UniString( rTypeId ); 783 // Versions Resource Klassenzeiger ans Ende setzen 784 rTypeId.GetResMgr()->Increment( sizeof( RSHEADER_TYPE ) ); 785 } 786 } 787 bInUse = sal_False; 788 } 789 790 return aTypStr; 791 } 792 793 // ----------------------------------------------------------------------- 794 795 void ResMgr::RscError_Impl( const sal_Char* pMessage, ResMgr* pResMgr, 796 RESOURCE_TYPE nRT, sal_uInt32 nId, 797 std::vector< ImpRCStack >& rResStack, int nDepth ) 798 { 799 // create a separate ResMgr with its own stack 800 // first get a second reference of the InternalResMgr 801 InternalResMgr* pImp = 802 ResMgrContainer::get().getResMgr( pResMgr->pImpRes->aPrefix, 803 pResMgr->pImpRes->aLocale, 804 true ); 805 806 ResMgr* pNewResMgr = new ResMgr( pImp ); 807 808 ByteString aStr = OUStringToOString( pResMgr->GetFileName(), RTL_TEXTENCODING_UTF8 ); 809 if ( aStr.Len() ) 810 aStr += '\n'; 811 812 aStr.Append( "Class: " ); 813 aStr.Append( ByteString( GetTypeRes_Impl( ResId( nRT, *pNewResMgr ) ), RTL_TEXTENCODING_UTF8 ) ); 814 aStr.Append( ", Id: " ); 815 aStr.Append( ByteString::CreateFromInt32( (long)nId ) ); 816 aStr.Append( ". " ); 817 aStr.Append( pMessage ); 818 819 aStr.Append( "\nResource Stack\n" ); 820 while( nDepth > 0 ) 821 { 822 aStr.Append( "Class: " ); 823 aStr.Append( ByteString( GetTypeRes_Impl( ResId( rResStack[nDepth].pResource->GetRT(), *pNewResMgr ) ), RTL_TEXTENCODING_UTF8 ) ); 824 aStr.Append( ", Id: " ); 825 aStr.Append( ByteString::CreateFromInt32( (long)rResStack[nDepth].pResource->GetId() ) ); 826 nDepth--; 827 } 828 829 // clean up 830 delete pNewResMgr; 831 832 DBG_ERROR( aStr.GetBuffer() ); 833 } 834 835 #endif 836 837 // ======================================================================= 838 839 static void RscException_Impl() 840 { 841 switch ( vos::OSignalHandler::raise( OSL_SIGNAL_USER_RESOURCEFAILURE, (void*)"" ) ) 842 { 843 case vos::OSignalHandler::TAction_CallNextHandler: 844 abort(); 845 846 case vos::OSignalHandler::TAction_Ignore: 847 return; 848 849 case vos::OSignalHandler::TAction_AbortApplication: 850 abort(); 851 852 case vos::OSignalHandler::TAction_KillApplication: 853 exit(-1); 854 } 855 } 856 857 // ======================================================================= 858 859 void ImpRCStack::Init( ResMgr* pMgr, const Resource* pObj, sal_uInt32 Id ) 860 { 861 pResource = NULL; 862 pClassRes = NULL; 863 Flags = RC_NOTYPE; 864 aResHandle = NULL; 865 pResObj = pObj; 866 nId = Id & ~RSC_DONTRELEASE; //TLX: Besser Init aendern 867 pResMgr = pMgr; 868 if ( !(Id & RSC_DONTRELEASE) ) 869 Flags |= RC_AUTORELEASE; 870 } 871 872 // ----------------------------------------------------------------------- 873 874 void ImpRCStack::Clear() 875 { 876 pResource = NULL; 877 pClassRes = NULL; 878 Flags = RC_NOTYPE; 879 aResHandle = NULL; 880 pResObj = NULL; 881 nId = 0; 882 pResMgr = NULL; 883 } 884 885 // ----------------------------------------------------------------------- 886 887 static RSHEADER_TYPE* LocalResource( const ImpRCStack* pStack, 888 RESOURCE_TYPE nRTType, 889 sal_uInt32 nId ) 890 { 891 // Gibt die Position der Resource zurueck, wenn sie gefunden wurde. 892 // Ansonsten gibt die Funktion Null zurueck. 893 RSHEADER_TYPE* pTmp; // Zeiger auf Kind-Resourceobjekte 894 RSHEADER_TYPE* pEnd; // Zeiger auf das Ende der Resource 895 896 if ( pStack->pResource && pStack->pClassRes ) 897 { 898 pTmp = (RSHEADER_TYPE*) 899 ((sal_uInt8*)pStack->pResource + pStack->pResource->GetLocalOff()); 900 pEnd = (RSHEADER_TYPE*) 901 ((sal_uInt8*)pStack->pResource + pStack->pResource->GetGlobOff()); 902 while ( pTmp != pEnd ) 903 { 904 if ( pTmp->GetRT() == nRTType && pTmp->GetId() == nId ) 905 return pTmp; 906 pTmp = (RSHEADER_TYPE*)((sal_uInt8*)pTmp + pTmp->GetGlobOff()); 907 } 908 } 909 910 return NULL; 911 } 912 913 // ======================================================================= 914 915 void* ResMgr::pEmptyBuffer = NULL; 916 917 void* ResMgr::getEmptyBuffer() 918 { 919 if( ! pEmptyBuffer ) 920 pEmptyBuffer = rtl_allocateZeroMemory( 1024 ); 921 return pEmptyBuffer; 922 } 923 924 void ResMgr::DestroyAllResMgr() 925 { 926 { 927 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); 928 if( pEmptyBuffer ) 929 { 930 rtl_freeMemory( pEmptyBuffer ); 931 pEmptyBuffer = NULL; 932 } 933 ResMgrContainer::release(); 934 } 935 delete pResMgrMutex; 936 pResMgrMutex = NULL; 937 } 938 939 // ----------------------------------------------------------------------- 940 941 void ResMgr::Init( const OUString& rFileName ) 942 { 943 (void) rFileName; // avoid warning about unused parameter 944 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); 945 946 if ( !pImpRes ) 947 { 948 #ifdef DBG_UTIL 949 ByteString aStr( "Resourcefile not found:\n" ); 950 aStr += ByteString( OUStringToOString( rFileName, RTL_TEXTENCODING_UTF8 ) ); 951 DBG_ERROR( aStr.GetBuffer() ); 952 #endif 953 RscException_Impl(); 954 } 955 #ifdef DBG_UTIL 956 else 957 { 958 void* aResHandle = 0; // Hilfvariable fuer Resource 959 void* pVoid; // Zeiger auf die Resource 960 961 pVoid = pImpRes->LoadGlobalRes( RSC_VERSIONCONTROL, RSCVERSION_ID, 962 &aResHandle ); 963 if ( pVoid ) 964 pImpRes->FreeGlobalRes( aResHandle, pVoid ); 965 else 966 { 967 ByteString aStr( "Wrong version:\n" ); 968 aStr += ByteString( OUStringToOString( pImpRes->aFileName, RTL_TEXTENCODING_UTF8 ) ); 969 DbgError( aStr.GetBuffer() ); 970 } 971 } 972 #endif 973 nCurStack = -1; 974 aStack.clear(); 975 pFallbackResMgr = pOriginalResMgr = NULL; 976 incStack(); 977 } 978 979 // ----------------------------------------------------------------------- 980 981 ResMgr::ResMgr( InternalResMgr * pImpMgr ) 982 { 983 pImpRes = pImpMgr; 984 Init( pImpMgr->aFileName ); 985 } 986 987 // ----------------------------------------------------------------------- 988 989 ResMgr::~ResMgr() 990 { 991 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); 992 993 ResMgrContainer::get().freeResMgr( pImpRes ); 994 995 // clean up possible left rc stack frames 996 while( nCurStack > 0 ) 997 { 998 if( ( aStack[nCurStack].Flags & (RC_GLOBAL | RC_NOTFOUND) ) == RC_GLOBAL ) 999 pImpRes->FreeGlobalRes( aStack[nCurStack].aResHandle, 1000 aStack[nCurStack].pResource ); 1001 nCurStack--; 1002 } 1003 } 1004 1005 1006 void ResMgr::incStack() 1007 { 1008 nCurStack++; 1009 if( nCurStack >= int(aStack.size()) ) 1010 aStack.push_back( ImpRCStack() ); 1011 aStack[nCurStack].Clear(); 1012 1013 DBG_ASSERT( nCurStack < 32, "Resource stack unreasonably large" ); 1014 } 1015 1016 void ResMgr::decStack() 1017 { 1018 DBG_ASSERT( nCurStack > 0, "resource stack underrun !" ); 1019 if( (aStack[nCurStack].Flags & RC_FALLBACK_UP) ) 1020 { 1021 nCurStack--; 1022 // warning: this will delete *this, see below 1023 pOriginalResMgr->decStack(); 1024 } 1025 else 1026 { 1027 ImpRCStack& rTop = aStack[nCurStack]; 1028 if( (rTop.Flags & RC_FALLBACK_DOWN) ) 1029 { 1030 #if OSL_DEBUG_LEVEL > 1 1031 OSL_TRACE( "returning from fallback %s\n", 1032 OUStringToOString(pFallbackResMgr->GetFileName(), osl_getThreadTextEncoding() ).getStr() ); 1033 #endif 1034 delete pFallbackResMgr; 1035 pFallbackResMgr = NULL; 1036 } 1037 nCurStack--; 1038 } 1039 } 1040 1041 #ifdef DBG_UTIL 1042 1043 void ResMgr::TestStack( const Resource* pResObj ) 1044 { 1045 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); 1046 1047 if ( DbgIsResource() ) 1048 { 1049 for( int i = 1; i <= nCurStack; ++i ) 1050 { 1051 if ( aStack[i].pResObj == pResObj ) 1052 { 1053 #ifdef DBG_UTIL 1054 RscError_Impl( "Resource not freed! ", this, 1055 aStack[i].pResource->GetRT(), 1056 aStack[i].pResource->GetId(), 1057 aStack, i-1 ); 1058 #endif 1059 } 1060 } 1061 } 1062 } 1063 1064 #else 1065 1066 void ResMgr::TestStack( const Resource* ) 1067 { 1068 } 1069 1070 #endif 1071 1072 // ----------------------------------------------------------------------- 1073 sal_Bool ResMgr::IsAvailable( const ResId& rId, const Resource* pResObj ) const 1074 { 1075 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); 1076 1077 sal_Bool bAvailable = sal_False; 1078 RSHEADER_TYPE* pClassRes = rId.GetpResource(); 1079 RESOURCE_TYPE nRT = rId.GetRT2(); 1080 sal_uInt32 nId = rId.GetId(); 1081 const ResMgr* pMgr = rId.GetResMgr(); 1082 1083 if ( !pMgr ) 1084 pMgr = this; 1085 1086 if( pMgr->pFallbackResMgr ) 1087 { 1088 ResId aId( rId ); 1089 aId.SetResMgr( NULL ); 1090 return pMgr->pFallbackResMgr->IsAvailable( aId, pResObj ); 1091 } 1092 1093 if ( !pResObj || pResObj == pMgr->aStack[pMgr->nCurStack].pResObj ) 1094 { 1095 if ( !pClassRes ) 1096 pClassRes = LocalResource( &pMgr->aStack[pMgr->nCurStack], nRT, nId ); 1097 if ( pClassRes ) 1098 { 1099 if ( pClassRes->GetRT() == nRT ) 1100 bAvailable = sal_True; 1101 } 1102 } 1103 1104 // vieleicht globale Resource 1105 if ( !pClassRes ) 1106 bAvailable = pMgr->pImpRes->IsGlobalAvailable( nRT, nId ); 1107 1108 return bAvailable; 1109 } 1110 1111 // ----------------------------------------------------------------------- 1112 1113 void* ResMgr::GetClass() 1114 { 1115 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); 1116 1117 if( pFallbackResMgr ) 1118 return pFallbackResMgr->GetClass(); 1119 1120 return aStack[nCurStack].pClassRes; 1121 } 1122 1123 // ----------------------------------------------------------------------- 1124 1125 sal_Bool ResMgr::GetResource( const ResId& rId, const Resource* pResObj ) 1126 { 1127 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); 1128 1129 if( pFallbackResMgr ) 1130 { 1131 ResId aId( rId ); 1132 aId.SetResMgr( NULL ); 1133 return pFallbackResMgr->GetResource( aId, pResObj ); 1134 } 1135 1136 ResMgr* pMgr = rId.GetResMgr(); 1137 if ( pMgr && (this != pMgr) ) 1138 return pMgr->GetResource( rId, pResObj ); 1139 1140 // normally Increment will pop the context; this is 1141 // not possible in RC_NOTFOUND case, so pop a frame here 1142 ImpRCStack* pTop = &aStack[nCurStack]; 1143 if( (pTop->Flags & RC_NOTFOUND) ) 1144 { 1145 decStack(); 1146 } 1147 1148 RSHEADER_TYPE* pClassRes = rId.GetpResource(); 1149 RESOURCE_TYPE nRT = rId.GetRT2(); 1150 sal_uInt32 nId = rId.GetId(); 1151 1152 incStack(); 1153 pTop = &aStack[nCurStack]; 1154 pTop->Init( pMgr, pResObj, nId | 1155 (rId.IsAutoRelease() ? 0 : RSC_DONTRELEASE) ); 1156 1157 if ( pClassRes ) 1158 { 1159 if ( pClassRes->GetRT() == nRT ) 1160 pTop->pClassRes = pClassRes; 1161 else 1162 { 1163 #ifdef DBG_UTIL 1164 RscError_Impl( "Different class and resource type!", 1165 this, nRT, nId, aStack, nCurStack-1 ); 1166 #endif 1167 pTop->Flags |= RC_NOTFOUND; 1168 pTop->pClassRes = getEmptyBuffer(); 1169 pTop->pResource = (RSHEADER_TYPE*)pTop->pClassRes; 1170 return sal_False; 1171 } 1172 } 1173 else 1174 { 1175 OSL_ENSURE( nCurStack > 0, "stack of 1 to shallow" ); 1176 pTop->pClassRes = LocalResource( &aStack[nCurStack-1], nRT, nId ); 1177 } 1178 1179 if ( pTop->pClassRes ) 1180 // lokale Resource, nicht system Resource 1181 pTop->pResource = (RSHEADER_TYPE *)pTop->pClassRes; 1182 else 1183 { 1184 pTop->pClassRes = pImpRes->LoadGlobalRes( nRT, nId, &pTop->aResHandle ); 1185 if ( pTop->pClassRes ) 1186 { 1187 pTop->Flags |= RC_GLOBAL; 1188 pTop->pResource = (RSHEADER_TYPE *)pTop->pClassRes; 1189 } 1190 else 1191 { 1192 // try to get a fallback resource 1193 pFallbackResMgr = CreateFallbackResMgr( rId, pResObj ); 1194 if( pFallbackResMgr ) 1195 { 1196 pTop->Flags |= RC_FALLBACK_DOWN; 1197 #ifdef DBG_UTIL 1198 ByteString aMess( "found resource " ); 1199 aMess.Append( ByteString::CreateFromInt32( nId ) ); 1200 aMess.Append( " in fallback " ); 1201 aMess.Append( ByteString( OUStringToOString( pFallbackResMgr->GetFileName(), osl_getThreadTextEncoding() ) ) ); 1202 aMess.Append( "\n" ); 1203 RscError_Impl( aMess.GetBuffer(), 1204 this, nRT, nId, aStack, nCurStack-1 ); 1205 #endif 1206 } 1207 else 1208 { 1209 #ifdef DBG_UTIL 1210 RscError_Impl( "Cannot load resource! ", 1211 this, nRT, nId, aStack, nCurStack-1 ); 1212 #endif 1213 pTop->Flags |= RC_NOTFOUND; 1214 pTop->pClassRes = getEmptyBuffer(); 1215 pTop->pResource = (RSHEADER_TYPE*)pTop->pClassRes; 1216 return sal_False; 1217 } 1218 } 1219 } 1220 1221 return sal_True; 1222 } 1223 1224 // ----------------------------------------------------------------------- 1225 1226 void * ResMgr::GetResourceSkipHeader( const ResId& rResId, ResMgr ** ppResMgr ) 1227 { 1228 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); 1229 1230 DBG_ASSERT( rResId.GetResMgr(), "illegal ResId without ResMgr" ); 1231 *ppResMgr = rResId.GetResMgr(); 1232 if( *ppResMgr ) 1233 { 1234 (*ppResMgr)->GetResource( rResId ); 1235 (*ppResMgr)->Increment( sizeof( RSHEADER_TYPE ) ); 1236 return (*ppResMgr)->GetClass(); 1237 } 1238 return getEmptyBuffer(); 1239 } 1240 1241 // ----------------------------------------------------------------------- 1242 1243 void ResMgr::PopContext( const Resource* pResObj ) 1244 { 1245 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); 1246 1247 if( pFallbackResMgr ) 1248 { 1249 pFallbackResMgr->PopContext( pResObj ); 1250 return; 1251 } 1252 1253 #ifdef DBG_UTIL 1254 if ( DbgIsResource() ) 1255 { 1256 if ( (aStack[nCurStack].pResObj != pResObj) || nCurStack == 0 ) 1257 { 1258 RscError_Impl( "Cannot free resource! ", this, 1259 RSC_NOTYPE, 0, aStack, nCurStack ); 1260 } 1261 } 1262 #endif 1263 1264 if ( nCurStack > 0 ) 1265 { 1266 ImpRCStack* pTop = &aStack[nCurStack]; 1267 #ifdef DBG_UTIL 1268 if ( DbgIsResource() && !(pTop->Flags & RC_NOTFOUND) ) 1269 { 1270 void* pRes = (sal_uInt8*)pTop->pResource + 1271 pTop->pResource->GetLocalOff(); 1272 1273 if ( pTop->pClassRes != pRes ) 1274 { 1275 RscError_Impl( "Classpointer not at the end!", 1276 this, pTop->pResource->GetRT(), 1277 pTop->pResource->GetId(), 1278 aStack, nCurStack-1 ); 1279 } 1280 } 1281 #endif 1282 1283 // Resource freigeben 1284 if( (pTop->Flags & (RC_GLOBAL | RC_NOTFOUND)) == RC_GLOBAL ) 1285 // kann auch Fremd-Ressource sein 1286 pImpRes->FreeGlobalRes( pTop->aResHandle, pTop->pResource ); 1287 decStack(); 1288 } 1289 } 1290 1291 // ----------------------------------------------------------------------- 1292 1293 RSHEADER_TYPE* ResMgr::CreateBlock( const ResId& rId ) 1294 { 1295 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); 1296 1297 if( pFallbackResMgr ) 1298 { 1299 ResId aId( rId ); 1300 aId.SetResMgr( NULL ); 1301 return pFallbackResMgr->CreateBlock( aId ); 1302 } 1303 1304 RSHEADER_TYPE* pHeader = NULL; 1305 if ( GetResource( rId ) ) 1306 { 1307 // Der Zeiger steht am Anfang, deswegen zeigt der Klassen-Pointer 1308 // auf den Header und die restliche Groesse ist die Gesammte. 1309 pHeader = (RSHEADER_TYPE*)rtl_allocateMemory( GetRemainSize() ); 1310 memcpy( pHeader, GetClass(), GetRemainSize() ); 1311 Increment( pHeader->GetLocalOff() ); //ans Ende setzen 1312 if ( pHeader->GetLocalOff() != pHeader->GetGlobOff() ) 1313 // Hat Sub-Ressourcen, deshalb extra freigeben 1314 PopContext(); 1315 } 1316 1317 return pHeader; 1318 } 1319 1320 // ------------------------------------------------------------------ 1321 1322 sal_Int16 ResMgr::GetShort( void * pShort ) 1323 { 1324 return ((*((sal_uInt8*)pShort + 0) << 8) | 1325 (*((sal_uInt8*)pShort + 1) << 0) ); 1326 } 1327 1328 // ------------------------------------------------------------------ 1329 1330 sal_Int32 ResMgr::GetLong( void * pLong ) 1331 { 1332 return ((*((sal_uInt8*)pLong + 0) << 24) | 1333 (*((sal_uInt8*)pLong + 1) << 16) | 1334 (*((sal_uInt8*)pLong + 2) << 8) | 1335 (*((sal_uInt8*)pLong + 3) << 0) ); 1336 } 1337 1338 // ------------------------------------------------------------------ 1339 1340 sal_uInt64 ResMgr::GetUInt64( void* pDatum ) 1341 { 1342 return ((sal_uInt64(*((sal_uInt8*)pDatum + 0)) << 56) | 1343 (sal_uInt64(*((sal_uInt8*)pDatum + 1)) << 48) | 1344 (sal_uInt64(*((sal_uInt8*)pDatum + 2)) << 40) | 1345 (sal_uInt64(*((sal_uInt8*)pDatum + 3)) << 32) | 1346 (sal_uInt64(*((sal_uInt8*)pDatum + 4)) << 24) | 1347 (sal_uInt64(*((sal_uInt8*)pDatum + 5)) << 16) | 1348 (sal_uInt64(*((sal_uInt8*)pDatum + 6)) << 8) | 1349 (sal_uInt64(*((sal_uInt8*)pDatum + 7)) << 0) ); 1350 } 1351 1352 // ----------------------------------------------------------------------- 1353 sal_uInt32 ResMgr::GetStringWithoutHook( UniString& rStr, const sal_uInt8* pStr ) 1354 { 1355 sal_uInt32 nLen=0; 1356 sal_uInt32 nRet = GetStringSize( pStr, nLen ); 1357 UniString aString( (sal_Char*)pStr, RTL_TEXTENCODING_UTF8, 1358 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_MAPTOPRIVATE | 1359 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT | 1360 RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT ); 1361 rStr = aString; 1362 return nRet; 1363 } 1364 1365 sal_uInt32 ResMgr::GetString( UniString& rStr, const sal_uInt8* pStr ) 1366 { 1367 UniString aString; 1368 sal_uInt32 nRet = GetStringWithoutHook( aString, pStr ); 1369 if ( pImplResHookProc ) 1370 pImplResHookProc( aString ); 1371 rStr = aString; 1372 return nRet; 1373 } 1374 1375 sal_uInt32 ResMgr::GetByteString( rtl::OString& rStr, const sal_uInt8* pStr ) 1376 { 1377 sal_uInt32 nLen=0; 1378 sal_uInt32 nRet = GetStringSize( pStr, nLen ); 1379 rStr = rtl::OString( (const sal_Char*)pStr, nLen ); 1380 return nRet; 1381 } 1382 1383 // ------------------------------------------------------------------ 1384 1385 sal_uInt32 ResMgr::GetStringSize( const sal_uInt8* pStr, sal_uInt32& nLen ) 1386 { 1387 nLen = static_cast< sal_uInt32 >( strlen( (const char*)pStr ) ); 1388 return GetStringSize( nLen ); 1389 } 1390 1391 // ----------------------------------------------------------------------- 1392 1393 sal_uInt32 ResMgr::GetRemainSize() 1394 { 1395 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); 1396 1397 if( pFallbackResMgr ) 1398 return pFallbackResMgr->GetRemainSize(); 1399 1400 const ImpRCStack& rTop = aStack[nCurStack]; 1401 return (sal_uInt32)((long)(sal_uInt8 *)rTop.pResource + 1402 rTop.pResource->GetLocalOff() - 1403 (long)(sal_uInt8 *)rTop.pClassRes); 1404 } 1405 1406 // ----------------------------------------------------------------------- 1407 1408 void* ResMgr::Increment( sal_uInt32 nSize ) 1409 { 1410 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); 1411 1412 if( pFallbackResMgr ) 1413 return pFallbackResMgr->Increment( nSize ); 1414 1415 ImpRCStack& rStack = aStack[nCurStack]; 1416 if( (rStack.Flags & RC_NOTFOUND) ) 1417 return rStack.pClassRes; 1418 1419 sal_uInt8* pClassRes = (sal_uInt8*)rStack.pClassRes + nSize; 1420 1421 rStack.pClassRes = pClassRes; 1422 1423 RSHEADER_TYPE* pRes = rStack.pResource; 1424 1425 sal_uInt32 nLocalOff = pRes->GetLocalOff(); 1426 if ( (pRes->GetGlobOff() == nLocalOff) && 1427 (((char*)pRes + nLocalOff) == rStack.pClassRes) && 1428 (rStack.Flags & RC_AUTORELEASE)) 1429 { 1430 PopContext( rStack.pResObj ); 1431 } 1432 1433 return pClassRes; 1434 } 1435 1436 ResMgr* ResMgr::CreateFallbackResMgr( const ResId& rId, const Resource* pResource ) 1437 { 1438 ResMgr *pFallback = NULL; 1439 if( nCurStack > 0 ) 1440 { 1441 // get the next fallback level in resource file scope 1442 InternalResMgr* pRes = ResMgrContainer::get().getNextFallback( pImpRes ); 1443 if( pRes ) 1444 { 1445 // check that the fallback locale is not already in the chain of 1446 // fallbacks - prevent fallback loops 1447 ResMgr* pResMgr = this; 1448 while( pResMgr && 1449 ( pResMgr->pImpRes->aLocale.Language != pRes->aLocale.Language || 1450 pResMgr->pImpRes->aLocale.Country != pRes->aLocale.Country || 1451 pResMgr->pImpRes->aLocale.Variant != pRes->aLocale.Variant ) 1452 ) 1453 { 1454 pResMgr = pResMgr->pOriginalResMgr; 1455 } 1456 if( pResMgr ) 1457 { 1458 // found a recursion, no fallback possible 1459 ResMgrContainer::get().freeResMgr( pRes ); 1460 return NULL; 1461 } 1462 OSL_TRACE( "trying fallback: %s\n", OUStringToOString( pRes->aFileName, osl_getThreadTextEncoding() ).getStr() ); 1463 pFallback = new ResMgr( pRes ); 1464 pFallback->pOriginalResMgr = this; 1465 // try to recreate the resource stack 1466 bool bHaveStack = true; 1467 for( int i = 1; i < nCurStack; i++ ) 1468 { 1469 if( !aStack[i].pResource ) 1470 { 1471 bHaveStack = false; 1472 break; 1473 } 1474 ResId aId( aStack[i].pResource->GetId(), *pFallbackResMgr ); 1475 aId.SetRT( aStack[i].pResource->GetRT() ); 1476 if( !pFallback->GetResource( aId ) ) 1477 { 1478 bHaveStack = false; 1479 break; 1480 } 1481 } 1482 if( bHaveStack ) 1483 { 1484 ResId aId( rId.GetId(), *pFallback ); 1485 aId.SetRT( rId.GetRT() ); 1486 if( !pFallback->GetResource( aId, pResource ) ) 1487 bHaveStack = false; 1488 else 1489 pFallback->aStack[pFallback->nCurStack].Flags |= RC_FALLBACK_UP; 1490 } 1491 if( !bHaveStack ) 1492 { 1493 delete pFallback; 1494 pFallback = NULL; 1495 } 1496 } 1497 } 1498 return pFallback; 1499 } 1500 1501 //--------------------------------------------------------------------------- 1502 // 1503 // method left here for SDK compatibility, 1504 // used in "framework/source/services/substitutepathvars.cxx" 1505 // 1506 // phone numbers no longer in use for resource files 1507 // 1508 //--------------------------------------------------------------------------- 1509 1510 const char* ResMgr::GetLang( LanguageType& nType, sal_uInt16 nPrio ) 1511 { 1512 if ( nType == LANGUAGE_SYSTEM || nType == LANGUAGE_DONTKNOW ) 1513 nType = MsLangId::getSystemUILanguage(); 1514 1515 if ( nPrio == 0 ) 1516 { 1517 switch ( nType ) 1518 { 1519 case LANGUAGE_DANISH: 1520 return "45"; 1521 1522 case LANGUAGE_DUTCH: 1523 case LANGUAGE_DUTCH_BELGIAN: 1524 return "31"; 1525 1526 case LANGUAGE_ENGLISH: 1527 case LANGUAGE_ENGLISH_UK: 1528 case LANGUAGE_ENGLISH_EIRE: 1529 case LANGUAGE_ENGLISH_SAFRICA: 1530 case LANGUAGE_ENGLISH_JAMAICA: 1531 case LANGUAGE_ENGLISH_BELIZE: 1532 case LANGUAGE_ENGLISH_TRINIDAD: 1533 case LANGUAGE_ENGLISH_ZIMBABWE: 1534 case LANGUAGE_ENGLISH_PHILIPPINES: 1535 return "44"; 1536 1537 case LANGUAGE_ENGLISH_US: 1538 case LANGUAGE_ENGLISH_CAN: 1539 return "01"; 1540 1541 case LANGUAGE_ENGLISH_AUS: 1542 case LANGUAGE_ENGLISH_NZ: 1543 return "61"; 1544 case LANGUAGE_ESTONIAN: 1545 return "77"; 1546 1547 1548 case LANGUAGE_FINNISH: 1549 return "35"; 1550 1551 case LANGUAGE_FRENCH_CANADIAN: 1552 return "02"; 1553 1554 case LANGUAGE_FRENCH: 1555 case LANGUAGE_FRENCH_BELGIAN: 1556 case LANGUAGE_FRENCH_SWISS: 1557 case LANGUAGE_FRENCH_LUXEMBOURG: 1558 case LANGUAGE_FRENCH_MONACO: 1559 return "33"; 1560 1561 case LANGUAGE_GERMAN: 1562 case LANGUAGE_GERMAN_SWISS: 1563 case LANGUAGE_GERMAN_AUSTRIAN: 1564 case LANGUAGE_GERMAN_LUXEMBOURG: 1565 case LANGUAGE_GERMAN_LIECHTENSTEIN: 1566 return "49"; 1567 1568 case LANGUAGE_ITALIAN: 1569 case LANGUAGE_ITALIAN_SWISS: 1570 return "39"; 1571 1572 case LANGUAGE_NORWEGIAN: 1573 case LANGUAGE_NORWEGIAN_BOKMAL: 1574 return "47"; 1575 1576 case LANGUAGE_PORTUGUESE: 1577 return "03"; 1578 1579 case LANGUAGE_PORTUGUESE_BRAZILIAN: 1580 return "55"; 1581 1582 case LANGUAGE_SPANISH_DATED: 1583 case LANGUAGE_SPANISH_MEXICAN: 1584 case LANGUAGE_SPANISH_MODERN: 1585 case LANGUAGE_SPANISH_GUATEMALA: 1586 case LANGUAGE_SPANISH_COSTARICA: 1587 case LANGUAGE_SPANISH_PANAMA: 1588 case LANGUAGE_SPANISH_DOMINICAN_REPUBLIC: 1589 case LANGUAGE_SPANISH_VENEZUELA: 1590 case LANGUAGE_SPANISH_COLOMBIA: 1591 case LANGUAGE_SPANISH_PERU: 1592 case LANGUAGE_SPANISH_ARGENTINA: 1593 case LANGUAGE_SPANISH_ECUADOR: 1594 case LANGUAGE_SPANISH_CHILE: 1595 case LANGUAGE_SPANISH_URUGUAY: 1596 case LANGUAGE_SPANISH_PARAGUAY: 1597 case LANGUAGE_SPANISH_BOLIVIA: 1598 return "34"; 1599 1600 case LANGUAGE_SWEDISH: 1601 return "46"; 1602 1603 case LANGUAGE_POLISH: 1604 return "48"; 1605 case LANGUAGE_CZECH: 1606 return "42"; 1607 case LANGUAGE_SLOVENIAN: 1608 return "50"; 1609 case LANGUAGE_HUNGARIAN: 1610 return "36"; 1611 case LANGUAGE_RUSSIAN: 1612 return "07"; 1613 case LANGUAGE_SLOVAK: 1614 return "43"; 1615 case LANGUAGE_GREEK: 1616 return "30"; 1617 case LANGUAGE_TURKISH: 1618 return "90"; 1619 1620 case LANGUAGE_CHINESE_SIMPLIFIED: 1621 return "86"; 1622 case LANGUAGE_CHINESE_TRADITIONAL: 1623 return "88"; 1624 case LANGUAGE_JAPANESE: 1625 return "81"; 1626 case LANGUAGE_KOREAN: 1627 case LANGUAGE_KOREAN_JOHAB: 1628 return "82"; 1629 case LANGUAGE_THAI: 1630 return "66"; 1631 case LANGUAGE_HINDI: 1632 return "91"; 1633 1634 case LANGUAGE_ARABIC_PRIMARY_ONLY: 1635 case LANGUAGE_ARABIC_IRAQ: 1636 case LANGUAGE_ARABIC_EGYPT: 1637 case LANGUAGE_ARABIC_LIBYA: 1638 case LANGUAGE_ARABIC_ALGERIA: 1639 case LANGUAGE_ARABIC_MOROCCO: 1640 case LANGUAGE_ARABIC_TUNISIA: 1641 case LANGUAGE_ARABIC_OMAN: 1642 case LANGUAGE_ARABIC_YEMEN: 1643 case LANGUAGE_ARABIC_SYRIA: 1644 case LANGUAGE_ARABIC_JORDAN: 1645 case LANGUAGE_ARABIC_LEBANON: 1646 case LANGUAGE_ARABIC_KUWAIT: 1647 case LANGUAGE_ARABIC_UAE: 1648 case LANGUAGE_ARABIC_BAHRAIN: 1649 case LANGUAGE_ARABIC_QATAR: 1650 return "96"; 1651 1652 case LANGUAGE_HEBREW: 1653 return "97"; 1654 1655 case LANGUAGE_CATALAN: 1656 return "37"; 1657 1658 default: 1659 return "99"; 1660 } 1661 } 1662 else if ( nPrio == 1 ) 1663 { 1664 switch ( nType ) 1665 { 1666 case LANGUAGE_FRENCH_CANADIAN: 1667 return "33"; 1668 1669 case LANGUAGE_PORTUGUESE_BRAZILIAN: 1670 return "03"; 1671 1672 default: 1673 return NULL; 1674 } 1675 } 1676 else if ( nPrio == 2 ) 1677 return "01"; 1678 else if ( nPrio == 3 ) 1679 return "44"; 1680 else if ( nPrio == 4 ) 1681 return "49"; 1682 else 1683 return "99"; 1684 } 1685 1686 // ----------------------------------------------------------------------- 1687 1688 ResMgr* ResMgr::CreateResMgr( const sal_Char* pPrefixName, 1689 com::sun::star::lang::Locale aLocale ) 1690 { 1691 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); 1692 1693 OUString aPrefix( pPrefixName, strlen( pPrefixName ), osl_getThreadTextEncoding() ); 1694 1695 if( ! aLocale.Language.getLength() ) 1696 aLocale = ResMgrContainer::get().getDefLocale(); 1697 1698 InternalResMgr* pImp = ResMgrContainer::get().getResMgr( aPrefix, aLocale ); 1699 return pImp ? new ResMgr( pImp ) : NULL; 1700 } 1701 1702 // ----------------------------------------------------------------------- 1703 1704 ResMgr* ResMgr::SearchCreateResMgr( 1705 const sal_Char* pPrefixName, 1706 com::sun::star::lang::Locale& rLocale ) 1707 { 1708 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); 1709 1710 OUString aPrefix( pPrefixName, strlen( pPrefixName ), osl_getThreadTextEncoding() ); 1711 1712 if( ! rLocale.Language.getLength() ) 1713 rLocale = ResMgrContainer::get().getDefLocale(); 1714 1715 InternalResMgr* pImp = ResMgrContainer::get().getResMgr( aPrefix, rLocale ); 1716 return pImp ? new ResMgr( pImp ) : NULL; 1717 } 1718 1719 // ----------------------------------------------------------------------- 1720 1721 sal_Int16 ResMgr::ReadShort() 1722 { 1723 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); 1724 1725 if( pFallbackResMgr ) 1726 return pFallbackResMgr->ReadShort(); 1727 1728 sal_Int16 n = GetShort( GetClass() ); 1729 Increment( sizeof( sal_Int16 ) ); 1730 return n; 1731 } 1732 1733 // ----------------------------------------------------------------------- 1734 1735 sal_Int32 ResMgr::ReadLong() 1736 { 1737 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); 1738 1739 if( pFallbackResMgr ) 1740 return pFallbackResMgr->ReadLong(); 1741 1742 sal_Int32 n = GetLong( GetClass() ); 1743 Increment( sizeof( sal_Int32 ) ); 1744 return n; 1745 } 1746 1747 // ----------------------------------------------------------------------- 1748 1749 UniString ResMgr::ReadStringWithoutHook() 1750 { 1751 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); 1752 1753 if( pFallbackResMgr ) 1754 return pFallbackResMgr->ReadStringWithoutHook(); 1755 1756 UniString aRet; 1757 1758 const ImpRCStack& rTop = aStack[nCurStack]; 1759 if( (rTop.Flags & RC_NOTFOUND) ) 1760 { 1761 #if OSL_DEBUG_LEVEL > 0 1762 aRet = OUString( RTL_CONSTASCII_USTRINGPARAM( "<resource not found>" ) ); 1763 #endif 1764 } 1765 else 1766 Increment( GetStringWithoutHook( aRet, (const sal_uInt8*)GetClass() ) ); 1767 1768 return aRet; 1769 } 1770 1771 UniString ResMgr::ReadString() 1772 { 1773 UniString aRet = ReadStringWithoutHook(); 1774 if ( pImplResHookProc ) 1775 pImplResHookProc( aRet ); 1776 return aRet; 1777 } 1778 1779 rtl::OString ResMgr::ReadByteString() 1780 { 1781 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); 1782 1783 if( pFallbackResMgr ) 1784 return pFallbackResMgr->ReadByteString(); 1785 1786 rtl::OString aRet; 1787 1788 const ImpRCStack& rTop = aStack[nCurStack]; 1789 if( (rTop.Flags & RC_NOTFOUND) ) 1790 { 1791 #if OSL_DEBUG_LEVEL > 0 1792 aRet = OString( "<resource not found>" ); 1793 #endif 1794 } 1795 else 1796 Increment( GetByteString( aRet, (const sal_uInt8*)GetClass() ) ); 1797 1798 return aRet; 1799 } 1800 1801 // ----------------------------------------------------------------------- 1802 1803 rtl::OString ResMgr::GetAutoHelpId() 1804 { 1805 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); 1806 1807 if( pFallbackResMgr ) 1808 return pFallbackResMgr->GetAutoHelpId(); 1809 1810 OSL_ENSURE( nCurStack, "resource stack empty in Auto help id generation" ); 1811 if( nCurStack < 1 || nCurStack > 2 ) 1812 return rtl::OString(); 1813 1814 // prepare HID, start with resource prefix 1815 rtl::OStringBuffer aHID( 32 ); 1816 aHID.append( rtl::OUStringToOString( pImpRes->aPrefix, RTL_TEXTENCODING_UTF8 ) ); 1817 aHID.append( '.' ); 1818 1819 // append type 1820 const ImpRCStack *pRC = StackTop(); 1821 OSL_ENSURE( pRC, "missing resource stack level" ); 1822 1823 if ( nCurStack == 1 ) 1824 { 1825 // auto help ids for top level windows 1826 switch( pRC->pResource->GetRT() ) { 1827 case RSC_DOCKINGWINDOW: aHID.append( "DockingWindow" ); break; 1828 case RSC_WORKWIN: aHID.append( "WorkWindow" ); break; 1829 case RSC_MODELESSDIALOG: aHID.append( "ModelessDialog" ); break; 1830 case RSC_FLOATINGWINDOW: aHID.append( "FloatingWindow" ); break; 1831 case RSC_MODALDIALOG: aHID.append( "ModalDialog" ); break; 1832 case RSC_TABPAGE: aHID.append( "TabPage" ); break; 1833 default: return rtl::OString(); 1834 } 1835 } 1836 else 1837 { 1838 // only controls with the following parents get auto help ids 1839 const ImpRCStack *pRC1 = StackTop(1); 1840 switch( pRC1->pResource->GetRT() ) { 1841 case RSC_DOCKINGWINDOW: 1842 case RSC_WORKWIN: 1843 case RSC_MODELESSDIALOG: 1844 case RSC_FLOATINGWINDOW: 1845 case RSC_MODALDIALOG: 1846 case RSC_TABPAGE: 1847 // intentionally no breaks! 1848 // auto help ids for controls 1849 switch( pRC->pResource->GetRT() ) { 1850 case RSC_TABCONTROL: aHID.append( "TabControl" ); break; 1851 case RSC_RADIOBUTTON: aHID.append( "RadioButton" ); break; 1852 case RSC_CHECKBOX: aHID.append( "CheckBox" ); break; 1853 case RSC_TRISTATEBOX: aHID.append( "TriStateBox" ); break; 1854 case RSC_EDIT: aHID.append( "Edit" ); break; 1855 case RSC_MULTILINEEDIT: aHID.append( "MultiLineEdit" ); break; 1856 case RSC_MULTILISTBOX: aHID.append( "MultiListBox" ); break; 1857 case RSC_LISTBOX: aHID.append( "ListBox" ); break; 1858 case RSC_COMBOBOX: aHID.append( "ComboBox" ); break; 1859 case RSC_PUSHBUTTON: aHID.append( "PushButton" ); break; 1860 case RSC_SPINFIELD: aHID.append( "SpinField" ); break; 1861 case RSC_PATTERNFIELD: aHID.append( "PatternField" ); break; 1862 case RSC_NUMERICFIELD: aHID.append( "NumericField" ); break; 1863 case RSC_METRICFIELD: aHID.append( "MetricField" ); break; 1864 case RSC_CURRENCYFIELD: aHID.append( "CurrencyField" ); break; 1865 case RSC_DATEFIELD: aHID.append( "DateField" ); break; 1866 case RSC_TIMEFIELD: aHID.append( "TimeField" ); break; 1867 case RSC_IMAGERADIOBUTTON: aHID.append( "ImageRadioButton" ); break; 1868 case RSC_NUMERICBOX: aHID.append( "NumericBox" ); break; 1869 case RSC_METRICBOX: aHID.append( "MetricBox" ); break; 1870 case RSC_CURRENCYBOX: aHID.append( "CurrencyBox" ); break; 1871 case RSC_DATEBOX: aHID.append( "DateBox" ); break; 1872 case RSC_TIMEBOX: aHID.append( "TimeBox" ); break; 1873 case RSC_IMAGEBUTTON: aHID.append( "ImageButton" ); break; 1874 case RSC_MENUBUTTON: aHID.append( "MenuButton" ); break; 1875 case RSC_MOREBUTTON: aHID.append( "MoreButton" ); break; 1876 default: 1877 // no type, no auto HID 1878 return rtl::OString(); 1879 } 1880 break; 1881 default: 1882 return rtl::OString(); 1883 } 1884 } 1885 1886 // append resource id hierarchy 1887 for( int nOff = nCurStack-1; nOff >= 0; nOff-- ) 1888 { 1889 aHID.append( '.' ); 1890 pRC = StackTop( nOff ); 1891 1892 OSL_ENSURE( pRC->pResource, "missing resource in resource stack level !" ); 1893 if( pRC->pResource ) 1894 aHID.append( sal_Int32( pRC->pResource->GetId() ) ); 1895 } 1896 1897 return aHID.makeStringAndClear(); 1898 } 1899 1900 // ----------------------------------------------------------------------- 1901 1902 void ResMgr::SetReadStringHook( ResHookProc pProc ) 1903 { 1904 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); 1905 pImplResHookProc = pProc; 1906 } 1907 1908 // ----------------------------------------------------------------------- 1909 1910 ResHookProc ResMgr::GetReadStringHook() 1911 { 1912 return pImplResHookProc; 1913 } 1914 1915 // ----------------------------------------------------------------------- 1916 1917 void ResMgr::SetDefaultLocale( const com::sun::star::lang::Locale& rLocale ) 1918 { 1919 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); 1920 ResMgrContainer::get().setDefLocale( rLocale ); 1921 } 1922 1923 // ----------------------------------------------------------------------- 1924 1925 const OUString& ResMgr::GetFileName() const 1926 { 1927 return pImpRes->aFileName; 1928 } 1929 1930 // ======================================================================= 1931 1932 SimpleResMgr::SimpleResMgr( const sal_Char* pPrefixName, 1933 const ::com::sun::star::lang::Locale& rLocale ) 1934 { 1935 OUString aPrefix( pPrefixName, strlen( pPrefixName ), osl_getThreadTextEncoding() ); 1936 com::sun::star::lang::Locale aLocale( rLocale ); 1937 1938 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); 1939 if( ! aLocale.Language.getLength() ) 1940 aLocale = ResMgrContainer::get().getDefLocale(); 1941 1942 m_pResImpl = ResMgrContainer::get().getResMgr( aPrefix, aLocale, true ); 1943 DBG_ASSERT( m_pResImpl, "SimpleResMgr::SimpleResMgr : have no impl class !" ); 1944 } 1945 1946 // ----------------------------------------------------------------------- 1947 SimpleResMgr::SimpleResMgr( const ::rtl::OUString& _rPrefixName, ::com::sun::star::lang::Locale& _inout_Locale ) 1948 { 1949 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); 1950 m_pResImpl = ResMgrContainer::get().getResMgr( _rPrefixName, _inout_Locale, true ); 1951 } 1952 1953 // ----------------------------------------------------------------------- 1954 SimpleResMgr::~SimpleResMgr() 1955 { 1956 delete m_pResImpl; 1957 } 1958 1959 // ----------------------------------------------------------------------- 1960 SimpleResMgr* SimpleResMgr::Create( const sal_Char* pPrefixName, com::sun::star::lang::Locale aLocale ) 1961 { 1962 return new SimpleResMgr( pPrefixName, aLocale ); 1963 } 1964 1965 // ----------------------------------------------------------------------- 1966 bool SimpleResMgr::IsAvailable( RESOURCE_TYPE _resourceType, sal_uInt32 _resourceId ) 1967 { 1968 vos::OGuard aGuard(m_aAccessSafety); 1969 1970 if ( ( RSC_STRING != _resourceType ) && ( RSC_RESOURCE != _resourceType ) ) 1971 return false; 1972 1973 DBG_ASSERT( m_pResImpl, "SimpleResMgr::IsAvailable: have no impl class !" ); 1974 return m_pResImpl->IsGlobalAvailable( _resourceType, _resourceId ); 1975 } 1976 1977 // ----------------------------------------------------------------------- 1978 UniString SimpleResMgr::ReadString( sal_uInt32 nId ) 1979 { 1980 vos::OGuard aGuard(m_aAccessSafety); 1981 1982 DBG_ASSERT( m_pResImpl, "SimpleResMgr::ReadString : have no impl class !" ); 1983 // perhaps constructed with an invalid filename ? 1984 1985 UniString sReturn; 1986 if ( !m_pResImpl ) 1987 return sReturn; 1988 1989 void* pResHandle = NULL; 1990 InternalResMgr* pFallback = m_pResImpl; 1991 RSHEADER_TYPE* pResHeader = (RSHEADER_TYPE*)m_pResImpl->LoadGlobalRes( RSC_STRING, nId, &pResHandle ); 1992 if ( !pResHeader ) 1993 { 1994 osl::Guard<osl::Mutex> aGuard2( getResMgrMutex() ); 1995 1996 // try fallback 1997 while( ! pResHandle && pFallback ) 1998 { 1999 InternalResMgr* pOldFallback = pFallback; 2000 pFallback = ResMgrContainer::get().getNextFallback( pFallback ); 2001 if( pOldFallback != m_pResImpl ) 2002 ResMgrContainer::get().freeResMgr( pOldFallback ); 2003 if( pFallback ) 2004 { 2005 // handle possible recursion 2006 if( pFallback->aLocale.Language != m_pResImpl->aLocale.Language || 2007 pFallback->aLocale.Country != m_pResImpl->aLocale.Country || 2008 pFallback->aLocale.Variant != m_pResImpl->aLocale.Variant ) 2009 { 2010 pResHeader = (RSHEADER_TYPE*)pFallback->LoadGlobalRes( RSC_STRING, nId, &pResHandle ); 2011 } 2012 else 2013 { 2014 ResMgrContainer::get().freeResMgr( pFallback ); 2015 pFallback = NULL; 2016 } 2017 } 2018 } 2019 if( ! pResHandle ) 2020 // no such resource 2021 return sReturn; 2022 } 2023 2024 // sal_uIntPtr nLen = pResHeader->GetLocalOff() - sizeof(RSHEADER_TYPE); 2025 ResMgr::GetString( sReturn, (const sal_uInt8*)(pResHeader+1) ); 2026 2027 // not neccessary with te current implementation which holds the string table permanently, but to be sure .... 2028 // note: pFallback cannot be NULL here and is either the fallback or m_pResImpl 2029 pFallback->FreeGlobalRes( pResHeader, pResHandle ); 2030 if( m_pResImpl != pFallback ) 2031 { 2032 osl::Guard<osl::Mutex> aGuard2( getResMgrMutex() ); 2033 2034 ResMgrContainer::get().freeResMgr( pFallback ); 2035 } 2036 return sReturn; 2037 } 2038 2039 // ----------------------------------------------------------------------- 2040 2041 const ::com::sun::star::lang::Locale& SimpleResMgr::GetLocale() const 2042 { 2043 DBG_ASSERT( IsValid(), "SimpleResMgr::ReadBlob: invalid, this will crash!" ); 2044 return m_pResImpl->aLocale; 2045 } 2046 2047 // ----------------------------------------------------------------------- 2048 2049 sal_uInt32 SimpleResMgr::ReadBlob( sal_uInt32 nId, void** pBuffer ) 2050 { 2051 vos::OGuard aGuard(m_aAccessSafety); 2052 2053 DBG_ASSERT( m_pResImpl, "SimpleResMgr::ReadBlob : have no impl class !" ); 2054 2055 // perhaps constructed with an invalid filename ? 2056 DBG_ASSERT( pBuffer, "SimpleResMgr::ReadBlob : invalid argument !" ); 2057 *pBuffer = NULL; 2058 2059 void* pResHandle = NULL; 2060 InternalResMgr* pFallback = m_pResImpl; 2061 RSHEADER_TYPE* pResHeader = (RSHEADER_TYPE*)m_pResImpl->LoadGlobalRes( RSC_RESOURCE, nId, &pResHandle ); 2062 DBG_ASSERT( pResHeader, "SimpleResMgr::ReadBlob : couldn't find the resource with the given id !" ); 2063 2064 if ( !pResHeader ) 2065 { 2066 osl::Guard<osl::Mutex> aGuard2( getResMgrMutex() ); 2067 2068 // try fallback 2069 while( ! pResHandle && pFallback ) 2070 { 2071 InternalResMgr* pOldFallback = pFallback; 2072 pFallback = ResMgrContainer::get().getNextFallback( pFallback ); 2073 if( pOldFallback != m_pResImpl ) 2074 ResMgrContainer::get().freeResMgr( pOldFallback ); 2075 if( pFallback ) 2076 { 2077 // handle possible recursion 2078 if( pFallback->aLocale.Language != m_pResImpl->aLocale.Language || 2079 pFallback->aLocale.Country != m_pResImpl->aLocale.Country || 2080 pFallback->aLocale.Variant != m_pResImpl->aLocale.Variant ) 2081 { 2082 pResHeader = (RSHEADER_TYPE*)pFallback->LoadGlobalRes( RSC_RESOURCE, nId, &pResHandle ); 2083 } 2084 else 2085 { 2086 ResMgrContainer::get().freeResMgr( pFallback ); 2087 pFallback = NULL; 2088 } 2089 } 2090 } 2091 if( ! pResHandle ) 2092 // no exception handling, this would require the locking of the solar mutex which isn't allowed within this class 2093 return 0; 2094 } 2095 2096 DBG_ASSERT( pResHandle == NULL, "SimpleResMgr::ReadBlob : behaviour of LoadGlobalRes changed !" ); 2097 // if pResHandle is not NULL the FreeBlob wouldn't have to delete the pointer given as pBuffer, but 2098 // FreeBlob doesn't know that so it would probably crash .... 2099 2100 sal_uInt32 nRemaining = pResHeader->GetLocalOff() - sizeof(RSHEADER_TYPE); 2101 *pBuffer = (void*)(((sal_uInt8*)pResHeader) + sizeof(RSHEADER_TYPE)); 2102 2103 // free an eventual fallback InternalResMgr 2104 if( m_pResImpl != pFallback ) 2105 { 2106 osl::Guard<osl::Mutex> aGuard2( getResMgrMutex() ); 2107 2108 ResMgrContainer::get().freeResMgr( pFallback ); 2109 } 2110 2111 return nRemaining; 2112 } 2113 2114 // ----------------------------------------------------------------------- 2115 2116 void SimpleResMgr::FreeBlob( void* pBuffer ) 2117 { 2118 void* pCompleteBuffer = (void*)(((sal_uInt8*)pBuffer) - sizeof(RSHEADER_TYPE)); 2119 rtl_freeMemory(pCompleteBuffer); 2120 } 2121