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