Branch libreoffice-5-0-4
[LibreOffice.git] / tools / source / rc / resmgr.cxx
blobd17c315b030af0d6df5201f4c7eb9e1c8c293fc0
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_folders.h>
22 #include <sal/config.h>
24 #include <cassert>
26 #include <string.h>
27 #include <stdio.h>
28 #include <stdlib.h>
30 #include <tools/debug.hxx>
31 #include <tools/stream.hxx>
32 #include <tools/resmgr.hxx>
33 #include <tools/rc.hxx>
34 #include <tools/rcid.h>
35 #include <osl/endian.h>
36 #include <osl/process.h>
37 #include <osl/thread.h>
38 #include <osl/file.hxx>
39 #include <osl/mutex.hxx>
40 #include <osl/signal.h>
41 #include <rtl/ustrbuf.hxx>
42 #include <rtl/strbuf.hxx>
43 #include <sal/log.hxx>
44 #include <rtl/instance.hxx>
45 #include <rtl/bootstrap.hxx>
46 #include <i18nlangtag/languagetag.hxx>
47 #include <i18nlangtag/mslangid.hxx>
48 #include <tools/simplerm.hxx>
50 #include <algorithm>
51 #include <functional>
52 #include <list>
53 #include <set>
54 #include <unordered_map>
56 using namespace osl;
58 // for thread safety
59 static osl::Mutex* pResMgrMutex = NULL;
61 static osl::Mutex& getResMgrMutex()
63 if( !pResMgrMutex )
65 osl::Guard<osl::Mutex> aGuard( *osl::Mutex::getGlobalMutex() );
66 if( ! pResMgrMutex )
67 pResMgrMutex = new osl::Mutex();
69 return *pResMgrMutex;
72 struct ImpContent;
74 class InternalResMgr
76 friend class ResMgr;
77 friend class SimpleResMgr;
78 friend class ResMgrContainer;
80 ImpContent * pContent;
81 sal_uInt32 nOffCorrection;
82 sal_uInt8 * pStringBlock;
83 SvStream * pStm;
84 bool bEqual2Content;
85 sal_uInt32 nEntries;
86 OUString aFileName;
87 OUString aPrefix;
88 OUString aResName;
89 bool bSingular;
90 LanguageTag aLocale;
91 std::unordered_map<sal_uInt64, int>* pResUseDump;
93 InternalResMgr( const OUString& rFileURL,
94 const OUString& aPrefix,
95 const OUString& aResName,
96 const LanguageTag& rLocale );
97 ~InternalResMgr();
98 bool Create();
100 bool IsGlobalAvailable( RESOURCE_TYPE nRT, sal_uInt32 nId ) const;
101 void * LoadGlobalRes( RESOURCE_TYPE nRT, sal_uInt32 nId,
102 void **pResHandle );
103 public:
104 static void FreeGlobalRes( void *, void * );
107 class ResMgrContainer
109 static ResMgrContainer* pOneInstance;
111 struct ContainerElement
113 InternalResMgr* pResMgr;
114 OUString aFileURL;
115 int nRefCount;
116 int nLoadCount;
118 ContainerElement() :
119 pResMgr( NULL ),
120 nRefCount( 0 ),
121 nLoadCount( 0 )
125 std::unordered_map< OUString, ContainerElement, OUStringHash> m_aResFiles;
126 LanguageTag m_aDefLocale;
128 ResMgrContainer() : m_aDefLocale( LANGUAGE_SYSTEM) { init(); }
129 ~ResMgrContainer();
131 void init();
133 public:
134 static ResMgrContainer& get();
135 static void release();
137 InternalResMgr* getResMgr( const OUString& rPrefix,
138 LanguageTag& rLocale,
139 bool bForceNewInstance = false
141 InternalResMgr* getNextFallback( InternalResMgr* pResMgr );
143 void freeResMgr( InternalResMgr* pResMgr );
145 void setDefLocale( const LanguageTag& rLocale )
146 { m_aDefLocale = rLocale; }
147 const LanguageTag& getDefLocale() const
148 { return m_aDefLocale; }
151 ResMgrContainer* ResMgrContainer::pOneInstance = NULL;
153 ResMgrContainer& ResMgrContainer::get()
155 if( ! pOneInstance )
156 pOneInstance = new ResMgrContainer();
157 return *pOneInstance;
160 ResMgrContainer::~ResMgrContainer()
162 for( std::unordered_map< OUString, ContainerElement, OUStringHash >::iterator it =
163 m_aResFiles.begin(); it != m_aResFiles.end(); ++it )
165 OSL_TRACE( "Resource file %s loaded %d times",
166 OUStringToOString( it->second.aFileURL, osl_getThreadTextEncoding() ).getStr(),
167 it->second.nLoadCount );
168 delete it->second.pResMgr;
172 void ResMgrContainer::release()
174 delete pOneInstance;
175 pOneInstance = NULL;
178 void ResMgrContainer::init()
180 assert( m_aResFiles.empty() );
182 // get resource path
183 OUString uri("$BRAND_BASE_DIR/" LIBO_SHARE_RESOURCE_FOLDER "/");
184 rtl::Bootstrap::expandMacros(uri); //TODO: detect failure
186 // collect all possible resource files
187 Directory aDir( uri );
188 if( aDir.open() == FileBase::E_None )
190 DirectoryItem aItem;
191 while( aDir.getNextItem( aItem ) == FileBase::E_None )
193 FileStatus aStatus(osl_FileStatus_Mask_FileName);
194 if( aItem.getFileStatus( aStatus ) == FileBase::E_None )
196 OUString aFileName = aStatus.getFileName();
197 if( ! aFileName.endsWithIgnoreAsciiCase( ".res" ) )
198 continue;
199 OUString aResName = aFileName.copy( 0, aFileName.getLength() - strlen(".res") );
200 if( aResName.isEmpty() )
201 continue;
202 assert( m_aResFiles.find( aResName ) == m_aResFiles.end() );
203 m_aResFiles[ aResName ].aFileURL = uri + aFileName;
204 SAL_INFO(
205 "tools.rc",
206 "ResMgrContainer: " << aResName << " -> "
207 << m_aResFiles[ aResName ].aFileURL );
211 else
212 SAL_WARN( "tools.rc", "opening dir " << uri << " failed" );
214 // set default language
215 LanguageType nLang = MsLangId::getSystemUILanguage();
216 m_aDefLocale.reset( nLang);
219 namespace
221 bool isAlreadyPureenUS(const LanguageTag &rLocale)
223 return ( rLocale.getLanguageType() == LANGUAGE_ENGLISH_US );
227 InternalResMgr* ResMgrContainer::getResMgr( const OUString& rPrefix,
228 LanguageTag& rLocale,
229 bool bForceNewInstance
232 LanguageTag aLocale( rLocale );
233 std::unordered_map< OUString, ContainerElement, OUStringHash >::iterator it = m_aResFiles.end();
235 ::std::vector< OUString > aFallbacks( aLocale.getFallbackStrings( true));
236 if (!isAlreadyPureenUS( aLocale))
237 aFallbacks.push_back( "en-US"); // last resort if all fallbacks fail
239 for (::std::vector< OUString >::const_iterator fb( aFallbacks.begin()); fb != aFallbacks.end(); ++fb)
241 OUString aSearch( rPrefix + *fb );
242 it = m_aResFiles.find( aSearch );
243 if( it != m_aResFiles.end() )
245 // ensure InternalResMgr existence
246 if( ! it->second.pResMgr )
248 InternalResMgr* pImp =
249 new InternalResMgr( it->second.aFileURL, rPrefix, it->first, aLocale );
250 if( ! pImp->Create() )
252 delete pImp;
253 continue;
255 it->second.pResMgr = pImp;
257 break;
260 // try if there is anything with this prefix at all
261 if( it == m_aResFiles.end() )
263 aLocale.reset( LANGUAGE_SYSTEM);
264 it = m_aResFiles.find( rPrefix );
265 if( it == m_aResFiles.end() )
267 for( it = m_aResFiles.begin(); it != m_aResFiles.end(); ++it )
269 if( it->first.matchIgnoreAsciiCase( rPrefix ) )
271 // ensure InternalResMgr existence
272 if( ! it->second.pResMgr )
274 InternalResMgr* pImp =
275 new InternalResMgr( it->second.aFileURL,
276 rPrefix,
277 it->first,
278 aLocale );
279 if( ! pImp->Create() )
281 delete pImp;
282 continue;
284 it->second.pResMgr = pImp;
286 // try to guess locale
287 sal_Int32 nIndex = rPrefix.getLength();
288 if (nIndex < it->first.getLength())
289 aLocale.reset( it->first.copy( nIndex));
290 else
292 SAL_WARN( "tools.rc", "ResMgrContainer::getResMgr: it->first " <<
293 it->first << " shorter than prefix " << rPrefix);
295 break;
300 // give up
301 if( it == m_aResFiles.end() )
303 OUString sURL = rPrefix + rLocale.getBcp47() + ".res";
304 if ( m_aResFiles.find(sURL) == m_aResFiles.end() )
306 m_aResFiles[ sURL ].aFileURL = sURL;
307 return getResMgr(rPrefix,rLocale,bForceNewInstance);
308 } // if ( m_aResFiles.find(sURL) == m_aResFiles.end() )
309 return NULL;
312 rLocale = aLocale;
313 // at this point it->second.pResMgr must be filled either by creating a new one
314 // (then the refcount is still 0) or because we already had one
315 InternalResMgr* pImp = it->second.pResMgr;
317 if( it->second.nRefCount == 0 )
318 it->second.nLoadCount++;
320 // for SimpleResMgr
321 if( bForceNewInstance )
323 if( it->second.nRefCount == 0 )
325 // shortcut: the match algorithm already created the InternalResMgr
326 // take it instead of creating yet another one
327 it->second.pResMgr = NULL;
328 pImp->bSingular = true;
330 else
332 pImp = new InternalResMgr( it->second.aFileURL, rPrefix, it->first, aLocale );
333 pImp->bSingular = true;
334 if( !pImp->Create() )
336 delete pImp;
337 pImp = NULL;
339 else
340 it->second.nLoadCount++;
343 else
344 it->second.nRefCount++;
346 return pImp;
349 InternalResMgr* ResMgrContainer::getNextFallback( InternalResMgr* pMgr )
351 /* TODO-BCP47: this is nasty, but the previous code simply stripped a
352 * locale's variant and country in subsequent calls to end up with language
353 * only and then fallback to en-US if all failed, so this is at least
354 * equivalent if not better. Maybe this method could be changed to get
355 * passed / remember a fallback list and an index within to pick the next.
356 * */
358 ::std::vector< OUString > aFallbacks( pMgr->aLocale.getFallbackStrings( true));
359 // The first is the locale itself, use next fallback or en-US.
360 /* TODO: what happens if the chain is "en-US", "en" -> "en-US", ...
361 * This was already an issue with the previous code. */
362 LanguageTag aLocale( ((aFallbacks.size() > 1) ? aFallbacks[1] : OUString( "en-US")));
363 InternalResMgr* pNext = getResMgr( pMgr->aPrefix, aLocale, pMgr->bSingular );
364 // prevent recursion
365 if( pNext == pMgr || ( pNext && pNext->aResName.equals( pMgr->aResName ) ) )
367 if( pNext->bSingular )
368 delete pNext;
369 pNext = NULL;
371 return pNext;
374 void ResMgrContainer::freeResMgr( InternalResMgr* pResMgr )
376 if( pResMgr->bSingular )
377 delete pResMgr;
378 else
380 std::unordered_map< OUString, ContainerElement, OUStringHash >::iterator it =
381 m_aResFiles.find( pResMgr->aResName );
382 if( it != m_aResFiles.end() )
384 DBG_ASSERT( it->second.nRefCount > 0, "InternalResMgr freed too often" );
385 if( it->second.nRefCount > 0 )
386 it->second.nRefCount--;
387 if( it->second.nRefCount == 0 )
389 delete it->second.pResMgr;
390 it->second.pResMgr = NULL;
396 #ifdef DBG_UTIL
397 void Resource::TestRes()
399 if( m_pResMgr )
400 m_pResMgr->TestStack( this );
402 #endif
404 struct ImpContent
406 sal_uInt64 nTypeAndId;
407 sal_uInt32 nOffset;
410 struct ImpContentLessCompare : public ::std::binary_function< ImpContent, ImpContent, bool>
412 inline bool operator() (const ImpContent& lhs, const ImpContent& rhs) const
414 return lhs.nTypeAndId < rhs.nTypeAndId;
418 static ResHookProc pImplResHookProc = 0;
420 InternalResMgr::InternalResMgr( const OUString& rFileURL,
421 const OUString& rPrefix,
422 const OUString& rResName,
423 const LanguageTag& rLocale )
424 : pContent( NULL )
425 , nOffCorrection( 0 )
426 , pStringBlock( NULL )
427 , pStm( NULL )
428 , bEqual2Content( true )
429 , nEntries( 0 )
430 , aFileName( rFileURL )
431 , aPrefix( rPrefix )
432 , aResName( rResName )
433 , bSingular( false )
434 , aLocale( rLocale )
435 , pResUseDump( 0 )
439 InternalResMgr::~InternalResMgr()
441 rtl_freeMemory(pContent);
442 rtl_freeMemory(pStringBlock);
443 delete pStm;
445 #ifdef DBG_UTIL
446 if( pResUseDump )
448 const sal_Char* pLogFile = getenv( "STAR_RESOURCE_LOGGING" );
449 if ( pLogFile )
451 SvFileStream aStm( OUString::createFromAscii( pLogFile ), StreamMode::WRITE );
452 aStm.Seek( STREAM_SEEK_TO_END );
453 OStringBuffer aLine("FileName: ");
454 aLine.append(OUStringToOString(aFileName,
455 RTL_TEXTENCODING_UTF8));
456 aStm.WriteLine(aLine.makeStringAndClear());
458 for( std::unordered_map<sal_uInt64, int>::const_iterator it = pResUseDump->begin();
459 it != pResUseDump->end(); ++it )
461 sal_uInt64 nKeyId = it->first;
462 aLine.append("Type/Id: ");
463 aLine.append(sal::static_int_cast< sal_Int32 >((nKeyId >> 32) & 0xFFFFFFFF));
464 aLine.append('/');
465 aLine.append(sal::static_int_cast< sal_Int32 >(nKeyId & 0xFFFFFFFF));
466 aStm.WriteLine(aLine.makeStringAndClear());
470 #endif
472 delete pResUseDump;
475 bool InternalResMgr::Create()
477 ResMgrContainer::get();
478 bool bDone = false;
480 pStm = new SvFileStream( aFileName, StreamMode::READ | StreamMode::SHARE_DENYWRITE | StreamMode::NOCREATE );
481 if( pStm->GetError() == 0 )
483 sal_Int32 lContLen = 0;
485 pStm->Seek( STREAM_SEEK_TO_END );
487 if( ( pInternalResMgr->pHead = (RSHEADER_TYPE *)mmap( 0, nResourceFileSize,
488 PROT_READ, MAP_PRIVATE,
489 fRes, 0 ) ) != (RSHEADER_TYPE *)-1)
491 pStm->SeekRel( - (int)sizeof( lContLen ) );
492 pStm->Read( &lContLen, sizeof( lContLen ) );
493 // is bigendian, swab to the right endian
494 lContLen = ResMgr::GetLong( &lContLen );
495 pStm->SeekRel( -lContLen );
496 // allocate stored ImpContent data (12 bytes per unit)
497 sal_uInt8* pContentBuf = static_cast<sal_uInt8*>(rtl_allocateMemory( lContLen ));
498 pStm->Read( pContentBuf, lContLen );
499 // allocate ImpContent space (sizeof(ImpContent) per unit, not necessarily 12)
500 pContent = static_cast<ImpContent *>(rtl_allocateMemory( sizeof(ImpContent)*lContLen/12 ));
501 // Shorten to number of ImpContent
502 nEntries = (sal_uInt32)lContLen / 12;
503 bEqual2Content = true;
504 bool bSorted = true;
505 if( nEntries )
507 #ifdef DBG_UTIL
508 const sal_Char* pLogFile = getenv( "STAR_RESOURCE_LOGGING" );
509 if ( pLogFile )
511 pResUseDump = new std::unordered_map<sal_uInt64, int>;
512 for( sal_uInt32 i = 0; i < nEntries; ++i )
513 (*pResUseDump)[pContent[i].nTypeAndId] = 1;
515 #endif
516 // swap the content to the right endian
517 pContent[0].nTypeAndId = ResMgr::GetUInt64( pContentBuf );
518 pContent[0].nOffset = ResMgr::GetLong( pContentBuf+8 );
519 sal_uInt32 nCount = nEntries - 1;
520 for( sal_uInt32 i = 0,j=1; i < nCount; ++i,++j )
522 // swap the content to the right endian
523 pContent[j].nTypeAndId = ResMgr::GetUInt64( pContentBuf + (12*j) );
524 pContent[j].nOffset = ResMgr::GetLong( pContentBuf + (12*j+8) );
525 if( pContent[i].nTypeAndId >= pContent[j].nTypeAndId )
526 bSorted = false;
527 if( (pContent[i].nTypeAndId & 0xFFFFFFFF00000000LL) == (pContent[j].nTypeAndId & 0xFFFFFFFF00000000LL)
528 && pContent[i].nOffset >= pContent[j].nOffset )
529 bEqual2Content = false;
532 rtl_freeMemory( pContentBuf );
533 OSL_ENSURE( bSorted, "content not sorted" );
534 OSL_ENSURE( bEqual2Content, "resource structure wrong" );
535 if( !bSorted )
536 ::std::sort(pContent,pContent+nEntries,ImpContentLessCompare());
537 // qsort( pContent, nEntries, sizeof( ImpContent ), Compare );
539 bDone = true;
542 return bDone;
546 bool InternalResMgr::IsGlobalAvailable( RESOURCE_TYPE nRT, sal_uInt32 nId ) const
548 // Anfang der Strings suchen
549 ImpContent aValue;
550 aValue.nTypeAndId = ((sal_uInt64(nRT) << 32) | nId);
551 ImpContent * pFind = ::std::lower_bound(pContent,
552 pContent + nEntries,
553 aValue,
554 ImpContentLessCompare());
555 return (pFind != (pContent + nEntries)) && (pFind->nTypeAndId == aValue.nTypeAndId);
559 void* InternalResMgr::LoadGlobalRes( RESOURCE_TYPE nRT, sal_uInt32 nId,
560 void **pResHandle )
562 #ifdef DBG_UTIL
563 if( pResUseDump )
564 pResUseDump->erase( (sal_uInt64(nRT) << 32) | nId );
565 #endif
566 // search beginning of string
567 ImpContent aValue;
568 aValue.nTypeAndId = ((sal_uInt64(nRT) << 32) | nId);
569 ImpContent* pEnd = (pContent + nEntries);
570 ImpContent* pFind = ::std::lower_bound( pContent,
571 pEnd,
572 aValue,
573 ImpContentLessCompare());
574 if( pFind && (pFind != pEnd) && (pFind->nTypeAndId == aValue.nTypeAndId) )
576 if( nRT == RSC_STRING && bEqual2Content )
578 // string optimization
579 if( !pStringBlock )
581 // search beginning of string
582 ImpContent * pFirst = pFind;
583 ImpContent * pLast = pFirst;
584 while( pFirst > pContent && ((pFirst -1)->nTypeAndId >> 32) == RSC_STRING )
585 --pFirst;
586 while( pLast < pEnd && (pLast->nTypeAndId >> 32) == RSC_STRING )
587 ++pLast;
588 nOffCorrection = pFirst->nOffset;
589 sal_uInt32 nSize;
590 --pLast;
591 pStm->Seek( pLast->nOffset );
592 RSHEADER_TYPE aHdr;
593 pStm->Read( &aHdr, sizeof( aHdr ) );
594 nSize = pLast->nOffset + aHdr.GetGlobOff() - nOffCorrection;
595 pStringBlock = static_cast<sal_uInt8*>(rtl_allocateMemory( nSize ));
596 pStm->Seek( pFirst->nOffset );
597 pStm->Read( pStringBlock, nSize );
599 *pResHandle = pStringBlock;
600 return pStringBlock + pFind->nOffset - nOffCorrection;
601 } // if( nRT == RSC_STRING && bEqual2Content )
602 else
604 *pResHandle = 0;
605 RSHEADER_TYPE aHeader;
606 pStm->Seek( pFind->nOffset );
607 pStm->Read( &aHeader, sizeof( RSHEADER_TYPE ) );
608 void * pRes = rtl_allocateMemory( aHeader.GetGlobOff() );
609 memcpy( pRes, &aHeader, sizeof( RSHEADER_TYPE ) );
610 pStm->Read( static_cast<sal_uInt8*>(pRes) + sizeof( RSHEADER_TYPE ),
611 aHeader.GetGlobOff() - sizeof( RSHEADER_TYPE ) );
612 return pRes;
614 } // if( pFind && (pFind != pEnd) && (pFind->nTypeAndId == nValue) )
615 *pResHandle = 0;
616 return NULL;
619 void InternalResMgr::FreeGlobalRes( void * pResHandle, void * pResource )
621 if ( !pResHandle )
622 // Free allocated resource
623 rtl_freeMemory(pResource);
626 #ifdef DBG_UTIL
628 OUString GetTypeRes_Impl( const ResId& rTypeId )
630 // Return on resource errors
631 static bool bInUse = false;
632 OUString aTypStr(OUString::number(rTypeId.GetId()));
634 if ( !bInUse )
636 bInUse = true;
638 ResId aResId( sal_uInt32(RSCVERSION_ID), *rTypeId.GetResMgr() );
639 aResId.SetRT( RSC_VERSIONCONTROL );
641 if ( rTypeId.GetResMgr()->GetResource( aResId ) )
643 rTypeId.SetRT( RSC_STRING );
644 if ( rTypeId.GetResMgr()->IsAvailable( rTypeId ) )
646 aTypStr = rTypeId.toString();
647 // Set class pointer to the end
648 rTypeId.GetResMgr()->Increment( sizeof( RSHEADER_TYPE ) );
651 bInUse = false;
654 return aTypStr;
657 void ResMgr::RscError_Impl( const sal_Char* pMessage, ResMgr* pResMgr,
658 RESOURCE_TYPE nRT, sal_uInt32 nId,
659 std::vector< ImpRCStack >& rResStack, int nDepth )
661 // create a separate ResMgr with its own stack
662 // first get a second reference of the InternalResMgr
663 InternalResMgr* pImp =
664 ResMgrContainer::get().getResMgr( pResMgr->pImpRes->aPrefix,
665 pResMgr->pImpRes->aLocale,
666 true );
668 ResMgr* pNewResMgr = new ResMgr( pImp );
670 OStringBuffer aStr(OUStringToOString(pResMgr->GetFileName(),
671 RTL_TEXTENCODING_UTF8));
673 if (aStr.getLength())
674 aStr.append('\n');
676 aStr.append("Class: ");
677 aStr.append(OUStringToOString(GetTypeRes_Impl(ResId(nRT, *pNewResMgr)),
678 RTL_TEXTENCODING_UTF8));
679 aStr.append(", Id: ");
680 aStr.append(static_cast<sal_Int32>(nId));
681 aStr.append(". ");
682 aStr.append(pMessage);
684 aStr.append("\nResource Stack\n");
685 while( nDepth > 0 )
687 aStr.append("Class: ");
688 aStr.append(OUStringToOString(GetTypeRes_Impl(
689 ResId(rResStack[nDepth].pResource->GetRT(), *pNewResMgr)),
690 RTL_TEXTENCODING_UTF8));
691 aStr.append(", Id: ");
692 aStr.append(static_cast<sal_Int32>(
693 rResStack[nDepth].pResource->GetId()));
694 nDepth--;
697 // clean up
698 delete pNewResMgr;
700 OSL_FAIL(aStr.getStr());
703 #endif
705 static void RscException_Impl()
707 switch ( osl_raiseSignal( OSL_SIGNAL_USER_RESOURCEFAILURE, (void*)"" ) )
709 case osl_Signal_ActCallNextHdl:
710 abort();
712 case osl_Signal_ActIgnore:
713 return;
715 case osl_Signal_ActAbortApp:
716 abort();
718 default:
719 case osl_Signal_ActKillApp:
720 exit(-1);
724 void ImpRCStack::Init( ResMgr* pMgr, const Resource* pObj, sal_uInt32 Id )
726 pResource = NULL;
727 pClassRes = NULL;
728 Flags = RCFlags::NONE;
729 aResHandle = NULL;
730 pResObj = pObj;
731 nId = Id & ~RSC_DONTRELEASE; //TLX: Besser Init aendern
732 pResMgr = pMgr;
733 if ( !(Id & RSC_DONTRELEASE) )
734 Flags |= RCFlags::AUTORELEASE;
737 void ImpRCStack::Clear()
739 pResource = NULL;
740 pClassRes = NULL;
741 Flags = RCFlags::NONE;
742 aResHandle = NULL;
743 pResObj = NULL;
744 nId = 0;
745 pResMgr = NULL;
748 static RSHEADER_TYPE* LocalResource( const ImpRCStack* pStack,
749 RESOURCE_TYPE nRTType,
750 sal_uInt32 nId )
752 // Returns position of the resource if found or NULL otherwise
753 RSHEADER_TYPE* pTmp; // Pointer to child resource
754 RSHEADER_TYPE* pEnd; // Pointer to the end of this resource
756 if ( pStack->pResource && pStack->pClassRes )
758 pTmp = reinterpret_cast<RSHEADER_TYPE*>
759 (reinterpret_cast<sal_uInt8*>(pStack->pResource) + pStack->pResource->GetLocalOff());
760 pEnd = reinterpret_cast<RSHEADER_TYPE*>
761 (reinterpret_cast<sal_uInt8*>(pStack->pResource) + pStack->pResource->GetGlobOff());
762 while ( pTmp != pEnd )
764 if ( pTmp->GetRT() == nRTType && pTmp->GetId() == nId )
765 return pTmp;
766 pTmp = reinterpret_cast<RSHEADER_TYPE*>(reinterpret_cast<sal_uInt8*>(pTmp) + pTmp->GetGlobOff());
770 return NULL;
773 void* ResMgr::pEmptyBuffer = NULL;
775 void* ResMgr::getEmptyBuffer()
777 if( ! pEmptyBuffer )
778 pEmptyBuffer = rtl_allocateZeroMemory( 1024 );
779 return pEmptyBuffer;
782 void ResMgr::DestroyAllResMgr()
785 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
786 if( pEmptyBuffer )
788 rtl_freeMemory( pEmptyBuffer );
789 pEmptyBuffer = NULL;
791 ResMgrContainer::release();
793 delete pResMgrMutex;
794 pResMgrMutex = NULL;
797 void ResMgr::Init( const OUString& rFileName )
799 (void) rFileName; // avoid warning about unused parameter
800 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
802 if ( !pImpRes )
804 #ifdef DBG_UTIL
805 OStringBuffer aStr("Resourcefile not found:\n");
806 aStr.append(OUStringToOString(rFileName, RTL_TEXTENCODING_UTF8));
807 OSL_FAIL(aStr.getStr());
808 #endif
809 RscException_Impl();
811 #ifdef DBG_UTIL
812 else
814 void* aResHandle = 0; // Helper variable for resource handles
815 void* pVoid; // Pointer on the resource
817 pVoid = pImpRes->LoadGlobalRes( RSC_VERSIONCONTROL, RSCVERSION_ID,
818 &aResHandle );
819 if ( pVoid )
820 InternalResMgr::FreeGlobalRes( aResHandle, pVoid );
821 else
823 SAL_WARN("tools.rc", "Wrong version: " << pImpRes->aFileName);
826 #endif
827 nCurStack = -1;
828 aStack.clear();
829 pFallbackResMgr = pOriginalResMgr = NULL;
830 incStack();
833 ResMgr::ResMgr( InternalResMgr * pImpMgr )
835 pImpRes = pImpMgr;
836 Init( pImpMgr->aFileName );
839 ResMgr::~ResMgr()
841 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
843 ResMgrContainer::get().freeResMgr( pImpRes );
845 // clean up possible left rc stack frames
846 while( nCurStack > 0 )
848 if( ( aStack[nCurStack].Flags & (RCFlags::GLOBAL | RCFlags::NOTFOUND) ) == RCFlags::GLOBAL )
849 InternalResMgr::FreeGlobalRes( aStack[nCurStack].aResHandle,
850 aStack[nCurStack].pResource );
851 nCurStack--;
855 void ResMgr::incStack()
857 nCurStack++;
858 if( nCurStack >= int(aStack.size()) )
859 aStack.push_back( ImpRCStack() );
860 aStack[nCurStack].Clear();
862 DBG_ASSERT( nCurStack < 32, "Resource stack unreasonably large" );
865 void ResMgr::decStack()
867 DBG_ASSERT( nCurStack > 0, "resource stack underrun !" );
868 if( (aStack[nCurStack].Flags & RCFlags::FALLBACK_UP) )
870 nCurStack--;
871 // warning: this will delete *this, see below
872 pOriginalResMgr->decStack();
874 else
876 ImpRCStack& rTop = aStack[nCurStack];
877 if( (rTop.Flags & RCFlags::FALLBACK_DOWN) )
879 #if OSL_DEBUG_LEVEL > 1
880 OSL_TRACE( "returning from fallback %s",
881 OUStringToOString(pFallbackResMgr->GetFileName(), osl_getThreadTextEncoding() ).getStr() );
882 #endif
883 delete pFallbackResMgr;
884 pFallbackResMgr = NULL;
886 nCurStack--;
890 #ifdef DBG_UTIL
892 void ResMgr::TestStack( const Resource* pResObj )
894 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
896 int upperLimit = nCurStack;
898 if ( upperLimit < 0 )
900 OSL_FAIL( "resource stack underrun!" );
901 upperLimit = aStack.size() - 1;
903 else if ( upperLimit >= static_cast<int>(aStack.size()) )
905 OSL_FAIL( "stack occupation index > allocated stack size" );
906 upperLimit = aStack.size() - 1;
909 if ( DbgIsResource() )
911 for( int i = 1; i <= upperLimit; ++i )
913 if ( aStack[i].pResObj == pResObj )
915 RscError_Impl( "Resource not freed! ", this,
916 aStack[i].pResource->GetRT(),
917 aStack[i].pResource->GetId(),
918 aStack, i-1 );
924 #endif
926 bool ResMgr::IsAvailable( const ResId& rId, const Resource* pResObj ) const
928 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
930 bool bAvailable = false;
931 RSHEADER_TYPE* pClassRes = rId.GetpResource();
932 RESOURCE_TYPE nRT = rId.GetRT2();
933 sal_uInt32 nId = rId.GetId();
934 const ResMgr* pMgr = rId.GetResMgr();
936 if ( !pMgr )
937 pMgr = this;
939 if( pMgr->pFallbackResMgr )
941 ResId aId( rId );
942 aId.SetResMgr( NULL );
943 return pMgr->pFallbackResMgr->IsAvailable( aId, pResObj );
946 if ( !pResObj || pResObj == pMgr->aStack[pMgr->nCurStack].pResObj )
948 if ( !pClassRes )
949 pClassRes = LocalResource( &pMgr->aStack[pMgr->nCurStack], nRT, nId );
950 if ( pClassRes )
952 if ( pClassRes->GetRT() == nRT )
953 bAvailable = true;
957 if ( !pClassRes )
958 bAvailable = pMgr->pImpRes->IsGlobalAvailable( nRT, nId );
960 return bAvailable;
963 void* ResMgr::GetClass()
965 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
967 if( pFallbackResMgr )
968 return pFallbackResMgr->GetClass();
970 return aStack[nCurStack].pClassRes;
973 bool ResMgr::GetResource( const ResId& rId, const Resource* pResObj )
975 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
977 if( pFallbackResMgr )
979 ResId aId( rId );
980 aId.SetResMgr( NULL );
981 return pFallbackResMgr->GetResource( aId, pResObj );
984 ResMgr* pMgr = rId.GetResMgr();
985 if ( pMgr && (this != pMgr) )
986 return pMgr->GetResource( rId, pResObj );
988 // normally Increment will pop the context; this is
989 // not possible in RCFlags::NOTFOUND case, so pop a frame here
990 ImpRCStack* pTop = &aStack[nCurStack];
991 if( (pTop->Flags & RCFlags::NOTFOUND) )
993 decStack();
996 RSHEADER_TYPE* pClassRes = rId.GetpResource();
997 RESOURCE_TYPE nRT = rId.GetRT2();
998 sal_uInt32 nId = rId.GetId();
1000 incStack();
1001 pTop = &aStack[nCurStack];
1002 pTop->Init( pMgr, pResObj, nId |
1003 (rId.IsAutoRelease() ? 0 : RSC_DONTRELEASE) );
1005 if ( pClassRes )
1007 if ( pClassRes->GetRT() == nRT )
1008 pTop->pClassRes = pClassRes;
1009 else
1011 #ifdef DBG_UTIL
1012 RscError_Impl( "Different class and resource type!",
1013 this, nRT, nId, aStack, nCurStack-1 );
1014 #endif
1015 pTop->Flags |= RCFlags::NOTFOUND;
1016 pTop->pClassRes = getEmptyBuffer();
1017 pTop->pResource = static_cast<RSHEADER_TYPE*>(pTop->pClassRes);
1018 return false;
1021 else
1023 OSL_ENSURE( nCurStack > 0, "stack of 1 to shallow" );
1024 pTop->pClassRes = LocalResource( &aStack[nCurStack-1], nRT, nId );
1027 if ( pTop->pClassRes )
1028 // local Resource, not a system Resource
1029 pTop->pResource = static_cast<RSHEADER_TYPE *>(pTop->pClassRes);
1030 else
1032 pTop->pClassRes = pImpRes->LoadGlobalRes( nRT, nId, &pTop->aResHandle );
1033 if ( pTop->pClassRes )
1035 pTop->Flags |= RCFlags::GLOBAL;
1036 pTop->pResource = static_cast<RSHEADER_TYPE *>(pTop->pClassRes);
1038 else
1040 // try to get a fallback resource
1041 pFallbackResMgr = CreateFallbackResMgr( rId, pResObj );
1042 if( pFallbackResMgr )
1044 pTop->Flags |= RCFlags::FALLBACK_DOWN;
1045 #ifdef DBG_UTIL
1046 OStringBuffer aMess("found resource ");
1047 aMess.append(static_cast<sal_Int32>(nId));
1048 aMess.append(" in fallback ");
1049 aMess.append(OUStringToOString(
1050 pFallbackResMgr->GetFileName(),
1051 osl_getThreadTextEncoding()));
1052 aMess.append('\n');
1053 RscError_Impl(aMess.getStr(),
1054 this, nRT, nId, aStack, nCurStack-1);
1055 #endif
1057 else
1059 #ifdef DBG_UTIL
1060 RscError_Impl( "Cannot load resource! ",
1061 this, nRT, nId, aStack, nCurStack-1 );
1062 #endif
1063 pTop->Flags |= RCFlags::NOTFOUND;
1064 pTop->pClassRes = getEmptyBuffer();
1065 pTop->pResource = static_cast<RSHEADER_TYPE*>(pTop->pClassRes);
1066 return false;
1071 return true;
1074 void * ResMgr::GetResourceSkipHeader( const ResId& rResId, ResMgr ** ppResMgr )
1076 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1078 *ppResMgr = rResId.GetResMgr();
1079 assert(*ppResMgr != nullptr);
1080 (*ppResMgr)->GetResource( rResId );
1081 (*ppResMgr)->Increment( sizeof( RSHEADER_TYPE ) );
1082 return (*ppResMgr)->GetClass();
1085 void ResMgr::PopContext( const Resource* pResObj )
1087 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1089 if( pFallbackResMgr )
1091 pFallbackResMgr->PopContext( pResObj );
1092 return;
1095 #ifdef DBG_UTIL
1096 if ( DbgIsResource() )
1098 if ( (aStack[nCurStack].pResObj != pResObj) || nCurStack == 0 )
1100 RscError_Impl( "Cannot free resource! ", this,
1101 RSC_NOTYPE, 0, aStack, nCurStack );
1104 #endif
1106 if ( nCurStack > 0 )
1108 ImpRCStack* pTop = &aStack[nCurStack];
1109 #ifdef DBG_UTIL
1110 if ( DbgIsResource() && !(pTop->Flags & RCFlags::NOTFOUND) )
1112 void* pRes = reinterpret_cast<sal_uInt8*>(pTop->pResource) +
1113 pTop->pResource->GetLocalOff();
1115 if ( pTop->pClassRes != pRes )
1117 RscError_Impl( "Classpointer not at the end!",
1118 this, pTop->pResource->GetRT(),
1119 pTop->pResource->GetId(),
1120 aStack, nCurStack-1 );
1123 #endif
1125 // free resource
1126 if( (pTop->Flags & (RCFlags::GLOBAL | RCFlags::NOTFOUND)) == RCFlags::GLOBAL )
1127 // free global resource if resource is foreign
1128 InternalResMgr::FreeGlobalRes( pTop->aResHandle, pTop->pResource );
1129 decStack();
1133 RSHEADER_TYPE* ResMgr::CreateBlock( const ResId& rId )
1135 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1137 if( pFallbackResMgr )
1139 ResId aId( rId );
1140 aId.SetResMgr( NULL );
1141 return pFallbackResMgr->CreateBlock( aId );
1144 RSHEADER_TYPE* pHeader = NULL;
1145 if ( GetResource( rId ) )
1147 // Pointer is at the beginning of the resource, thus
1148 // class pointer points to the header, and the remaining size
1149 // equals to total size of allocated memory
1150 pHeader = static_cast<RSHEADER_TYPE*>(rtl_allocateMemory( GetRemainSize() ));
1151 memcpy( pHeader, GetClass(), GetRemainSize() );
1152 Increment( pHeader->GetLocalOff() ); //ans Ende setzen
1153 if ( pHeader->GetLocalOff() != pHeader->GetGlobOff() )
1154 // Has sub-resources, thus release them as well
1155 PopContext();
1158 return pHeader;
1161 sal_Int16 ResMgr::GetShort( void * pShort )
1163 return ((*(static_cast<sal_uInt8*>(pShort) + 0) << 8) |
1164 (*(static_cast<sal_uInt8*>(pShort) + 1) << 0) );
1167 sal_Int32 ResMgr::GetLong( void * pLong )
1169 return ((*(static_cast<sal_uInt8*>(pLong) + 0) << 24) |
1170 (*(static_cast<sal_uInt8*>(pLong) + 1) << 16) |
1171 (*(static_cast<sal_uInt8*>(pLong) + 2) << 8) |
1172 (*(static_cast<sal_uInt8*>(pLong) + 3) << 0) );
1175 sal_uInt64 ResMgr::GetUInt64( void* pDatum )
1177 return ((sal_uInt64(*(static_cast<sal_uInt8*>(pDatum) + 0)) << 56) |
1178 (sal_uInt64(*(static_cast<sal_uInt8*>(pDatum) + 1)) << 48) |
1179 (sal_uInt64(*(static_cast<sal_uInt8*>(pDatum) + 2)) << 40) |
1180 (sal_uInt64(*(static_cast<sal_uInt8*>(pDatum) + 3)) << 32) |
1181 (sal_uInt64(*(static_cast<sal_uInt8*>(pDatum) + 4)) << 24) |
1182 (sal_uInt64(*(static_cast<sal_uInt8*>(pDatum) + 5)) << 16) |
1183 (sal_uInt64(*(static_cast<sal_uInt8*>(pDatum) + 6)) << 8) |
1184 (sal_uInt64(*(static_cast<sal_uInt8*>(pDatum) + 7)) << 0) );
1187 sal_uInt32 ResMgr::GetStringWithoutHook( OUString& rStr, const sal_uInt8* pStr )
1189 sal_uInt32 nLen=0;
1190 sal_uInt32 nRet = GetStringSize( pStr, nLen );
1191 const sal_Char* str = reinterpret_cast< const sal_Char* >( pStr );
1192 OUString aString( str, strlen( str ), RTL_TEXTENCODING_UTF8,
1193 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_MAPTOPRIVATE |
1194 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT |
1195 RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT );
1196 rStr = aString;
1197 return nRet;
1200 sal_uInt32 ResMgr::GetString( OUString& rStr, const sal_uInt8* pStr )
1202 OUString aString;
1203 sal_uInt32 nRet = GetStringWithoutHook( aString, pStr );
1204 if ( pImplResHookProc )
1205 aString = pImplResHookProc( aString );
1206 rStr = aString;
1207 return nRet;
1210 sal_uInt32 ResMgr::GetByteString( OString& rStr, const sal_uInt8* pStr )
1212 sal_uInt32 nLen=0;
1213 sal_uInt32 nRet = GetStringSize( pStr, nLen );
1214 rStr = OString( reinterpret_cast<const char*>(pStr), nLen );
1215 return nRet;
1218 sal_uInt32 ResMgr::GetStringSize( const sal_uInt8* pStr, sal_uInt32& nLen )
1220 nLen = static_cast< sal_uInt32 >( strlen( reinterpret_cast<const char*>(pStr) ) );
1221 return GetStringSize( nLen );
1224 sal_uInt32 ResMgr::GetRemainSize()
1226 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1228 if( pFallbackResMgr )
1229 return pFallbackResMgr->GetRemainSize();
1231 const ImpRCStack& rTop = aStack[nCurStack];
1232 return (sal_uInt32)(reinterpret_cast<sal_IntPtr>(rTop.pResource) +
1233 rTop.pResource->GetLocalOff() -
1234 reinterpret_cast<sal_IntPtr>(rTop.pClassRes));
1237 void* ResMgr::Increment( sal_uInt32 nSize )
1239 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1241 if( pFallbackResMgr )
1242 return pFallbackResMgr->Increment( nSize );
1244 ImpRCStack& rStack = aStack[nCurStack];
1245 if( (rStack.Flags & RCFlags::NOTFOUND) )
1246 return rStack.pClassRes;
1248 sal_uInt8* pClassRes = static_cast<sal_uInt8*>(rStack.pClassRes) + nSize;
1250 rStack.pClassRes = pClassRes;
1252 RSHEADER_TYPE* pRes = rStack.pResource;
1254 sal_uInt32 nLocalOff = pRes->GetLocalOff();
1255 if ( (pRes->GetGlobOff() == nLocalOff) &&
1256 ((reinterpret_cast<char*>(pRes) + nLocalOff) == rStack.pClassRes) &&
1257 (rStack.Flags & RCFlags::AUTORELEASE))
1259 PopContext( rStack.pResObj );
1262 return pClassRes;
1265 ResMgr* ResMgr::CreateFallbackResMgr( const ResId& rId, const Resource* pResource )
1267 ResMgr *pFallback = NULL;
1268 if( nCurStack > 0 )
1270 // get the next fallback level in resource file scope
1271 InternalResMgr* pRes = ResMgrContainer::get().getNextFallback( pImpRes );
1272 if( pRes )
1274 // check that the fallback locale is not already in the chain of
1275 // fallbacks - prevent fallback loops
1276 ResMgr* pResMgr = this;
1277 while( pResMgr && (pResMgr->pImpRes->aLocale != pRes->aLocale))
1279 pResMgr = pResMgr->pOriginalResMgr;
1281 if( pResMgr )
1283 // found a recursion, no fallback possible
1284 ResMgrContainer::get().freeResMgr( pRes );
1285 return NULL;
1287 OSL_TRACE( "trying fallback: %s", OUStringToOString( pRes->aFileName, osl_getThreadTextEncoding() ).getStr() );
1288 pFallback = new ResMgr( pRes );
1289 pFallback->pOriginalResMgr = this;
1290 // try to recreate the resource stack
1291 bool bHaveStack = true;
1292 for( int i = 1; i < nCurStack; i++ )
1294 if( !aStack[i].pResource )
1296 bHaveStack = false;
1297 break;
1299 ResId aId( aStack[i].pResource->GetId(), *pFallbackResMgr );
1300 aId.SetRT( aStack[i].pResource->GetRT() );
1301 if( !pFallback->GetResource( aId ) )
1303 bHaveStack = false;
1304 break;
1307 if( bHaveStack )
1309 ResId aId( rId.GetId(), *pFallback );
1310 aId.SetRT( rId.GetRT() );
1311 if( !pFallback->GetResource( aId, pResource ) )
1312 bHaveStack = false;
1313 else
1314 pFallback->aStack[pFallback->nCurStack].Flags |= RCFlags::FALLBACK_UP;
1316 if( !bHaveStack )
1318 delete pFallback;
1319 pFallback = NULL;
1323 return pFallback;
1326 ResMgr* ResMgr::CreateResMgr( const sal_Char* pPrefixName,
1327 const LanguageTag& _aLocale )
1329 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1331 OUString aPrefix( pPrefixName, strlen( pPrefixName ), osl_getThreadTextEncoding() );
1333 LanguageTag aLocale = _aLocale;
1334 if( aLocale.isSystemLocale() )
1335 aLocale = ResMgrContainer::get().getDefLocale();
1337 InternalResMgr* pImp = ResMgrContainer::get().getResMgr( aPrefix, aLocale );
1338 return pImp ? new ResMgr( pImp ) : NULL;
1341 ResMgr* ResMgr::SearchCreateResMgr(
1342 const sal_Char* pPrefixName,
1343 LanguageTag& rLocale )
1345 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1347 OUString aPrefix( pPrefixName, strlen( pPrefixName ), osl_getThreadTextEncoding() );
1349 if( rLocale.isSystemLocale() )
1350 rLocale = ResMgrContainer::get().getDefLocale();
1352 InternalResMgr* pImp = ResMgrContainer::get().getResMgr( aPrefix, rLocale );
1353 return pImp ? new ResMgr( pImp ) : NULL;
1356 sal_Int16 ResMgr::ReadShort()
1358 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1360 if( pFallbackResMgr )
1361 return pFallbackResMgr->ReadShort();
1363 sal_Int16 n = GetShort( GetClass() );
1364 Increment( sizeof( sal_Int16 ) );
1365 return n;
1368 sal_Int32 ResMgr::ReadLong()
1370 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1372 if( pFallbackResMgr )
1373 return pFallbackResMgr->ReadLong();
1375 sal_Int32 n = GetLong( GetClass() );
1376 Increment( sizeof( sal_Int32 ) );
1377 return n;
1380 OUString ResMgr::ReadStringWithoutHook()
1382 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1384 if( pFallbackResMgr )
1385 return pFallbackResMgr->ReadStringWithoutHook();
1387 OUString aRet;
1389 const ImpRCStack& rTop = aStack[nCurStack];
1390 if( (rTop.Flags & RCFlags::NOTFOUND) )
1392 #if OSL_DEBUG_LEVEL > 0
1393 aRet = "<resource not found>";
1394 #endif
1396 else
1397 Increment( GetStringWithoutHook( aRet, static_cast<const sal_uInt8*>(GetClass()) ) );
1399 return aRet;
1402 OUString ResMgr::ReadString()
1404 OUString aRet = ReadStringWithoutHook();
1405 if ( pImplResHookProc )
1406 aRet = pImplResHookProc( aRet );
1407 return aRet;
1410 OString ResMgr::ReadByteString()
1412 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1414 if( pFallbackResMgr )
1415 return pFallbackResMgr->ReadByteString();
1417 OString aRet;
1419 const ImpRCStack& rTop = aStack[nCurStack];
1420 if( (rTop.Flags & RCFlags::NOTFOUND) )
1422 #if OSL_DEBUG_LEVEL > 0
1423 aRet = OString( "<resource not found>" );
1424 #endif
1426 else
1427 Increment( GetByteString( aRet, static_cast<const sal_uInt8*>(GetClass()) ) );
1429 return aRet;
1432 OString ResMgr::GetAutoHelpId()
1434 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1436 if( pFallbackResMgr )
1437 return pFallbackResMgr->GetAutoHelpId();
1439 OSL_ENSURE( nCurStack, "resource stack empty in Auto help id generation" );
1440 if( nCurStack < 1 || nCurStack > 2 )
1441 return OString();
1443 // prepare HID, start with resource prefix
1444 OStringBuffer aHID( 32 );
1445 aHID.append( OUStringToOString( pImpRes->aPrefix, RTL_TEXTENCODING_UTF8 ) );
1446 aHID.append( '.' );
1448 // append type
1449 const ImpRCStack *pRC = StackTop();
1450 OSL_ENSURE( pRC, "missing resource stack level" );
1452 if ( nCurStack == 1 )
1454 // auto help ids for top level windows
1455 switch( pRC->pResource->GetRT() ) {
1456 case RSC_DOCKINGWINDOW: aHID.append( "DockingWindow" ); break;
1457 case RSC_WORKWIN: aHID.append( "WorkWindow" ); break;
1458 default: return OString();
1461 else
1463 // only controls with the following parents get auto help ids
1464 const ImpRCStack *pRC1 = StackTop(1);
1465 switch( pRC1->pResource->GetRT() ) {
1466 case RSC_DOCKINGWINDOW:
1467 case RSC_WORKWIN:
1468 // intentionally no breaks!
1469 // auto help ids for controls
1470 switch( pRC->pResource->GetRT() ) {
1471 case RSC_RADIOBUTTON: aHID.append( "RadioButton" ); break;
1472 case RSC_CHECKBOX: aHID.append( "CheckBox" ); break;
1473 case RSC_EDIT: aHID.append( "Edit" ); break;
1474 case RSC_LISTBOX: aHID.append( "ListBox" ); break;
1475 case RSC_COMBOBOX: aHID.append( "ComboBox" ); break;
1476 case RSC_PUSHBUTTON: aHID.append( "PushButton" ); break;
1477 case RSC_SPINFIELD: aHID.append( "SpinField" ); break;
1478 case RSC_NUMERICFIELD: aHID.append( "NumericField" ); break;
1479 case RSC_METRICFIELD: aHID.append( "MetricField" ); break;
1480 case RSC_IMAGEBUTTON: aHID.append( "ImageButton" ); break;
1481 default:
1482 // no type, no auto HID
1483 return OString();
1485 break;
1486 default:
1487 return OString();
1491 // append resource id hierarchy
1492 for( int nOff = nCurStack-1; nOff >= 0; nOff-- )
1494 aHID.append( '.' );
1495 pRC = StackTop( nOff );
1497 OSL_ENSURE( pRC->pResource, "missing resource in resource stack level !" );
1498 if( pRC->pResource )
1499 aHID.append( sal_Int32( pRC->pResource->GetId() ) );
1502 return aHID.makeStringAndClear();
1505 void ResMgr::SetReadStringHook( ResHookProc pProc )
1507 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1508 pImplResHookProc = pProc;
1511 ResHookProc ResMgr::GetReadStringHook()
1513 return pImplResHookProc;
1516 void ResMgr::SetDefaultLocale( const LanguageTag& rLocale )
1518 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1519 ResMgrContainer::get().setDefLocale( rLocale );
1522 const OUString& ResMgr::GetFileName() const
1524 return pImpRes->aFileName;
1527 SimpleResMgr::SimpleResMgr( const sal_Char* pPrefixName,
1528 const LanguageTag& rLocale )
1530 OUString aPrefix( pPrefixName, strlen( pPrefixName ), osl_getThreadTextEncoding() );
1531 LanguageTag aLocale( rLocale );
1533 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1534 if( aLocale.isSystemLocale() )
1535 aLocale = ResMgrContainer::get().getDefLocale();
1537 m_pResImpl = ResMgrContainer::get().getResMgr( aPrefix, aLocale, true );
1538 DBG_ASSERT( m_pResImpl, "SimpleResMgr::SimpleResMgr : have no impl class !" );
1541 SimpleResMgr::~SimpleResMgr()
1543 delete m_pResImpl;
1546 SimpleResMgr* SimpleResMgr::Create(const sal_Char* pPrefixName, const LanguageTag& rLocale)
1548 return new SimpleResMgr(pPrefixName, rLocale);
1551 bool SimpleResMgr::IsAvailable( RESOURCE_TYPE _resourceType, sal_uInt32 _resourceId )
1553 osl::MutexGuard aGuard(m_aAccessSafety);
1555 if ( ( RSC_STRING != _resourceType ) && ( RSC_RESOURCE != _resourceType ) )
1556 return false;
1558 DBG_ASSERT( m_pResImpl, "SimpleResMgr::IsAvailable: have no impl class !" );
1559 return m_pResImpl->IsGlobalAvailable( _resourceType, _resourceId );
1562 OUString SimpleResMgr::ReadString( sal_uInt32 nId )
1564 osl::MutexGuard aGuard(m_aAccessSafety);
1566 DBG_ASSERT( m_pResImpl, "SimpleResMgr::ReadString : have no impl class !" );
1567 // perhaps constructed with an invalid filename ?
1569 OUString sReturn;
1570 if ( !m_pResImpl )
1571 return sReturn;
1573 void* pResHandle = NULL;
1574 InternalResMgr* pFallback = m_pResImpl;
1575 RSHEADER_TYPE* pResHeader = static_cast<RSHEADER_TYPE*>(m_pResImpl->LoadGlobalRes( RSC_STRING, nId, &pResHandle ));
1576 if ( !pResHeader )
1578 osl::Guard<osl::Mutex> aGuard2( getResMgrMutex() );
1580 // try fallback
1581 while( ! pResHandle && pFallback )
1583 InternalResMgr* pOldFallback = pFallback;
1584 pFallback = ResMgrContainer::get().getNextFallback( pFallback );
1585 if( pOldFallback != m_pResImpl )
1586 ResMgrContainer::get().freeResMgr( pOldFallback );
1587 if( pFallback )
1589 // handle possible recursion
1590 if( pFallback->aLocale != m_pResImpl->aLocale )
1592 pResHeader = static_cast<RSHEADER_TYPE*>(pFallback->LoadGlobalRes( RSC_STRING, nId, &pResHandle ));
1594 else
1596 ResMgrContainer::get().freeResMgr( pFallback );
1597 pFallback = NULL;
1601 if( ! pResHandle )
1602 // no such resource
1603 return sReturn;
1606 // sal_uIntPtr nLen = pResHeader->GetLocalOff() - sizeof(RSHEADER_TYPE);
1607 ResMgr::GetString( sReturn, reinterpret_cast<sal_uInt8*>(pResHeader+1) );
1609 // not necessary with the current implementation which holds the string table permanently, but to be sure ....
1610 // note: pFallback cannot be NULL here and is either the fallback or m_pResImpl
1611 InternalResMgr::FreeGlobalRes( pResHeader, pResHandle );
1612 if( m_pResImpl != pFallback )
1614 osl::Guard<osl::Mutex> aGuard2( getResMgrMutex() );
1616 ResMgrContainer::get().freeResMgr( pFallback );
1618 return sReturn;
1621 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */