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