1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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>
54 #include <unordered_map>
59 static osl::Mutex
* pResMgrMutex
= NULL
;
61 static osl::Mutex
& getResMgrMutex()
65 osl::Guard
<osl::Mutex
> aGuard( *osl::Mutex::getGlobalMutex() );
67 pResMgrMutex
= new osl::Mutex();
77 friend class SimpleResMgr
;
78 friend class ResMgrContainer
;
80 ImpContent
* pContent
;
81 sal_uInt32 nOffCorrection
;
82 sal_uInt8
* pStringBlock
;
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
);
100 bool IsGlobalAvailable( RESOURCE_TYPE nRT
, sal_uInt32 nId
) const;
101 void * LoadGlobalRes( RESOURCE_TYPE nRT
, sal_uInt32 nId
,
104 static void FreeGlobalRes( void *, void * );
107 class ResMgrContainer
109 static ResMgrContainer
* pOneInstance
;
111 struct ContainerElement
113 InternalResMgr
* pResMgr
;
125 std::unordered_map
< OUString
, ContainerElement
, OUStringHash
> m_aResFiles
;
126 LanguageTag m_aDefLocale
;
128 ResMgrContainer() : m_aDefLocale( LANGUAGE_SYSTEM
) { init(); }
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()
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()
178 void ResMgrContainer::init()
180 assert( m_aResFiles
.empty() );
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
)
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" ) )
199 OUString aResName
= aFileName
.copy( 0, aFileName
.getLength() - strlen(".res") );
200 if( aResName
.isEmpty() )
202 assert( m_aResFiles
.find( aResName
) == m_aResFiles
.end() );
203 m_aResFiles
[ aResName
].aFileURL
= uri
+ aFileName
;
206 "ResMgrContainer: " << aResName
<< " -> "
207 << m_aResFiles
[ aResName
].aFileURL
);
212 SAL_WARN( "tools.rc", "opening dir " << uri
<< " failed" );
214 // set default language
215 LanguageType nLang
= MsLangId::getSystemUILanguage();
216 m_aDefLocale
.reset( nLang
);
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() )
255 it
->second
.pResMgr
= pImp
;
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
,
279 if( ! pImp
->Create() )
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
));
292 SAL_WARN( "tools.rc", "ResMgrContainer::getResMgr: it->first " <<
293 it
->first
<< " shorter than prefix " << rPrefix
);
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() )
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
++;
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;
332 pImp
= new InternalResMgr( it
->second
.aFileURL
, rPrefix
, it
->first
, aLocale
);
333 pImp
->bSingular
= true;
334 if( !pImp
->Create() )
340 it
->second
.nLoadCount
++;
344 it
->second
.nRefCount
++;
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.
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
);
365 if( pNext
== pMgr
|| ( pNext
&& pNext
->aResName
.equals( pMgr
->aResName
) ) )
367 if( pNext
->bSingular
)
374 void ResMgrContainer::freeResMgr( InternalResMgr
* pResMgr
)
376 if( pResMgr
->bSingular
)
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
;
397 void Resource::TestRes()
400 m_pResMgr
->TestStack( this );
406 sal_uInt64 nTypeAndId
;
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
)
425 , nOffCorrection( 0 )
426 , pStringBlock( NULL
)
428 , bEqual2Content( true )
430 , aFileName( rFileURL
)
432 , aResName( rResName
)
439 InternalResMgr::~InternalResMgr()
441 rtl_freeMemory(pContent
);
442 rtl_freeMemory(pStringBlock
);
448 const sal_Char
* pLogFile
= getenv( "STAR_RESOURCE_LOGGING" );
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));
465 aLine
.append(sal::static_int_cast
< sal_Int32
>(nKeyId
& 0xFFFFFFFF));
466 aStm
.WriteLine(aLine
.makeStringAndClear());
475 bool InternalResMgr::Create()
477 ResMgrContainer::get();
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;
508 const sal_Char
* pLogFile
= getenv( "STAR_RESOURCE_LOGGING" );
511 pResUseDump
= new std::unordered_map
<sal_uInt64
, int>;
512 for( sal_uInt32 i
= 0; i
< nEntries
; ++i
)
513 (*pResUseDump
)[pContent
[i
].nTypeAndId
] = 1;
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
)
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" );
536 ::std::sort(pContent
,pContent
+nEntries
,ImpContentLessCompare());
537 // qsort( pContent, nEntries, sizeof( ImpContent ), Compare );
546 bool InternalResMgr::IsGlobalAvailable( RESOURCE_TYPE nRT
, sal_uInt32 nId
) const
548 // Anfang der Strings suchen
550 aValue
.nTypeAndId
= ((sal_uInt64(nRT
) << 32) | nId
);
551 ImpContent
* pFind
= ::std::lower_bound(pContent
,
554 ImpContentLessCompare());
555 return (pFind
!= (pContent
+ nEntries
)) && (pFind
->nTypeAndId
== aValue
.nTypeAndId
);
559 void* InternalResMgr::LoadGlobalRes( RESOURCE_TYPE nRT
, sal_uInt32 nId
,
564 pResUseDump
->erase( (sal_uInt64(nRT
) << 32) | nId
);
566 // search beginning of string
568 aValue
.nTypeAndId
= ((sal_uInt64(nRT
) << 32) | nId
);
569 ImpContent
* pEnd
= (pContent
+ nEntries
);
570 ImpContent
* pFind
= ::std::lower_bound( pContent
,
573 ImpContentLessCompare());
574 if( pFind
&& (pFind
!= pEnd
) && (pFind
->nTypeAndId
== aValue
.nTypeAndId
) )
576 if( nRT
== RSC_STRING
&& bEqual2Content
)
578 // string optimization
581 // search beginning of string
582 ImpContent
* pFirst
= pFind
;
583 ImpContent
* pLast
= pFirst
;
584 while( pFirst
> pContent
&& ((pFirst
-1)->nTypeAndId
>> 32) == RSC_STRING
)
586 while( pLast
< pEnd
&& (pLast
->nTypeAndId
>> 32) == RSC_STRING
)
588 nOffCorrection
= pFirst
->nOffset
;
591 pStm
->Seek( pLast
->nOffset
);
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 )
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
) );
614 } // if( pFind && (pFind != pEnd) && (pFind->nTypeAndId == nValue) )
619 void InternalResMgr::FreeGlobalRes( void * pResHandle
, void * pResource
)
622 // Free allocated resource
623 rtl_freeMemory(pResource
);
628 OUString
GetTypeRes_Impl( const ResId
& rTypeId
)
630 // Return on resource errors
631 static bool bInUse
= false;
632 OUString
aTypStr(OUString::number(rTypeId
.GetId()));
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
) );
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
,
668 ResMgr
* pNewResMgr
= new ResMgr( pImp
);
670 OStringBuffer
aStr(OUStringToOString(pResMgr
->GetFileName(),
671 RTL_TEXTENCODING_UTF8
));
673 if (aStr
.getLength())
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
));
682 aStr
.append(pMessage
);
684 aStr
.append("\nResource Stack\n");
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()));
700 OSL_FAIL(aStr
.getStr());
705 static void RscException_Impl()
707 switch ( osl_raiseSignal( OSL_SIGNAL_USER_RESOURCEFAILURE
, (void*)"" ) )
709 case osl_Signal_ActCallNextHdl
:
712 case osl_Signal_ActIgnore
:
715 case osl_Signal_ActAbortApp
:
719 case osl_Signal_ActKillApp
:
724 void ImpRCStack::Init( ResMgr
* pMgr
, const Resource
* pObj
, sal_uInt32 Id
)
728 Flags
= RCFlags::NONE
;
731 nId
= Id
& ~RSC_DONTRELEASE
; //TLX: Besser Init aendern
733 if ( !(Id
& RSC_DONTRELEASE
) )
734 Flags
|= RCFlags::AUTORELEASE
;
737 void ImpRCStack::Clear()
741 Flags
= RCFlags::NONE
;
748 static RSHEADER_TYPE
* LocalResource( const ImpRCStack
* pStack
,
749 RESOURCE_TYPE nRTType
,
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
)
766 pTmp
= reinterpret_cast<RSHEADER_TYPE
*>(reinterpret_cast<sal_uInt8
*>(pTmp
) + pTmp
->GetGlobOff());
773 void* ResMgr::pEmptyBuffer
= NULL
;
775 void* ResMgr::getEmptyBuffer()
778 pEmptyBuffer
= rtl_allocateZeroMemory( 1024 );
782 void ResMgr::DestroyAllResMgr()
785 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
788 rtl_freeMemory( pEmptyBuffer
);
791 ResMgrContainer::release();
797 void ResMgr::Init( const OUString
& rFileName
)
799 (void) rFileName
; // avoid warning about unused parameter
800 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
805 OStringBuffer
aStr("Resourcefile not found:\n");
806 aStr
.append(OUStringToOString(rFileName
, RTL_TEXTENCODING_UTF8
));
807 OSL_FAIL(aStr
.getStr());
814 void* aResHandle
= 0; // Helper variable for resource handles
815 void* pVoid
; // Pointer on the resource
817 pVoid
= pImpRes
->LoadGlobalRes( RSC_VERSIONCONTROL
, RSCVERSION_ID
,
820 InternalResMgr::FreeGlobalRes( aResHandle
, pVoid
);
823 SAL_WARN("tools.rc", "Wrong version: " << pImpRes
->aFileName
);
829 pFallbackResMgr
= pOriginalResMgr
= NULL
;
833 ResMgr::ResMgr( InternalResMgr
* pImpMgr
)
836 Init( pImpMgr
->aFileName
);
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
);
855 void ResMgr::incStack()
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
) )
871 // warning: this will delete *this, see below
872 pOriginalResMgr
->decStack();
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() );
883 delete pFallbackResMgr
;
884 pFallbackResMgr
= NULL
;
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(),
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();
939 if( pMgr
->pFallbackResMgr
)
942 aId
.SetResMgr( NULL
);
943 return pMgr
->pFallbackResMgr
->IsAvailable( aId
, pResObj
);
946 if ( !pResObj
|| pResObj
== pMgr
->aStack
[pMgr
->nCurStack
].pResObj
)
949 pClassRes
= LocalResource( &pMgr
->aStack
[pMgr
->nCurStack
], nRT
, nId
);
952 if ( pClassRes
->GetRT() == nRT
)
958 bAvailable
= pMgr
->pImpRes
->IsGlobalAvailable( nRT
, nId
);
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
)
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
) )
996 RSHEADER_TYPE
* pClassRes
= rId
.GetpResource();
997 RESOURCE_TYPE nRT
= rId
.GetRT2();
998 sal_uInt32 nId
= rId
.GetId();
1001 pTop
= &aStack
[nCurStack
];
1002 pTop
->Init( pMgr
, pResObj
, nId
|
1003 (rId
.IsAutoRelease() ? 0 : RSC_DONTRELEASE
) );
1007 if ( pClassRes
->GetRT() == nRT
)
1008 pTop
->pClassRes
= pClassRes
;
1012 RscError_Impl( "Different class and resource type!",
1013 this, nRT
, nId
, aStack
, nCurStack
-1 );
1015 pTop
->Flags
|= RCFlags::NOTFOUND
;
1016 pTop
->pClassRes
= getEmptyBuffer();
1017 pTop
->pResource
= static_cast<RSHEADER_TYPE
*>(pTop
->pClassRes
);
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
);
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
);
1040 // try to get a fallback resource
1041 pFallbackResMgr
= CreateFallbackResMgr( rId
, pResObj
);
1042 if( pFallbackResMgr
)
1044 pTop
->Flags
|= RCFlags::FALLBACK_DOWN
;
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()));
1053 RscError_Impl(aMess
.getStr(),
1054 this, nRT
, nId
, aStack
, nCurStack
-1);
1060 RscError_Impl( "Cannot load resource! ",
1061 this, nRT
, nId
, aStack
, nCurStack
-1 );
1063 pTop
->Flags
|= RCFlags::NOTFOUND
;
1064 pTop
->pClassRes
= getEmptyBuffer();
1065 pTop
->pResource
= static_cast<RSHEADER_TYPE
*>(pTop
->pClassRes
);
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
);
1096 if ( DbgIsResource() )
1098 if ( (aStack
[nCurStack
].pResObj
!= pResObj
) || nCurStack
== 0 )
1100 RscError_Impl( "Cannot free resource! ", this,
1101 RSC_NOTYPE
, 0, aStack
, nCurStack
);
1106 if ( nCurStack
> 0 )
1108 ImpRCStack
* pTop
= &aStack
[nCurStack
];
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 );
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
);
1133 RSHEADER_TYPE
* ResMgr::CreateBlock( const ResId
& rId
)
1135 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1137 if( pFallbackResMgr
)
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
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
)
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
);
1200 sal_uInt32
ResMgr::GetString( OUString
& rStr
, const sal_uInt8
* pStr
)
1203 sal_uInt32 nRet
= GetStringWithoutHook( aString
, pStr
);
1204 if ( pImplResHookProc
)
1205 aString
= pImplResHookProc( aString
);
1210 sal_uInt32
ResMgr::GetByteString( OString
& rStr
, const sal_uInt8
* pStr
)
1213 sal_uInt32 nRet
= GetStringSize( pStr
, nLen
);
1214 rStr
= OString( reinterpret_cast<const char*>(pStr
), nLen
);
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
);
1265 ResMgr
* ResMgr::CreateFallbackResMgr( const ResId
& rId
, const Resource
* pResource
)
1267 ResMgr
*pFallback
= NULL
;
1270 // get the next fallback level in resource file scope
1271 InternalResMgr
* pRes
= ResMgrContainer::get().getNextFallback( pImpRes
);
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
;
1283 // found a recursion, no fallback possible
1284 ResMgrContainer::get().freeResMgr( pRes
);
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
)
1299 ResId
aId( aStack
[i
].pResource
->GetId(), *pFallbackResMgr
);
1300 aId
.SetRT( aStack
[i
].pResource
->GetRT() );
1301 if( !pFallback
->GetResource( aId
) )
1309 ResId
aId( rId
.GetId(), *pFallback
);
1310 aId
.SetRT( rId
.GetRT() );
1311 if( !pFallback
->GetResource( aId
, pResource
) )
1314 pFallback
->aStack
[pFallback
->nCurStack
].Flags
|= RCFlags::FALLBACK_UP
;
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
) );
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
) );
1380 OUString
ResMgr::ReadStringWithoutHook()
1382 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1384 if( pFallbackResMgr
)
1385 return pFallbackResMgr
->ReadStringWithoutHook();
1389 const ImpRCStack
& rTop
= aStack
[nCurStack
];
1390 if( (rTop
.Flags
& RCFlags::NOTFOUND
) )
1392 #if OSL_DEBUG_LEVEL > 0
1393 aRet
= "<resource not found>";
1397 Increment( GetStringWithoutHook( aRet
, static_cast<const sal_uInt8
*>(GetClass()) ) );
1402 OUString
ResMgr::ReadString()
1404 OUString aRet
= ReadStringWithoutHook();
1405 if ( pImplResHookProc
)
1406 aRet
= pImplResHookProc( aRet
);
1410 OString
ResMgr::ReadByteString()
1412 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1414 if( pFallbackResMgr
)
1415 return pFallbackResMgr
->ReadByteString();
1419 const ImpRCStack
& rTop
= aStack
[nCurStack
];
1420 if( (rTop
.Flags
& RCFlags::NOTFOUND
) )
1422 #if OSL_DEBUG_LEVEL > 0
1423 aRet
= OString( "<resource not found>" );
1427 Increment( GetByteString( aRet
, static_cast<const sal_uInt8
*>(GetClass()) ) );
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 )
1443 // prepare HID, start with resource prefix
1444 OStringBuffer
aHID( 32 );
1445 aHID
.append( OUStringToOString( pImpRes
->aPrefix
, RTL_TEXTENCODING_UTF8
) );
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();
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
:
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;
1482 // no type, no auto HID
1491 // append resource id hierarchy
1492 for( int nOff
= nCurStack
-1; nOff
>= 0; nOff
-- )
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()
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
) )
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 ?
1573 void* pResHandle
= NULL
;
1574 InternalResMgr
* pFallback
= m_pResImpl
;
1575 RSHEADER_TYPE
* pResHeader
= static_cast<RSHEADER_TYPE
*>(m_pResImpl
->LoadGlobalRes( RSC_STRING
, nId
, &pResHandle
));
1578 osl::Guard
<osl::Mutex
> aGuard2( getResMgrMutex() );
1581 while( ! pResHandle
&& pFallback
)
1583 InternalResMgr
* pOldFallback
= pFallback
;
1584 pFallback
= ResMgrContainer::get().getNextFallback( pFallback
);
1585 if( pOldFallback
!= m_pResImpl
)
1586 ResMgrContainer::get().freeResMgr( pOldFallback
);
1589 // handle possible recursion
1590 if( pFallback
->aLocale
!= m_pResImpl
->aLocale
)
1592 pResHeader
= static_cast<RSHEADER_TYPE
*>(pFallback
->LoadGlobalRes( RSC_STRING
, nId
, &pResHandle
));
1596 ResMgrContainer::get().freeResMgr( pFallback
);
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
);
1621 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */