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>
52 #include <boost/unordered_map.hpp>
60 static osl::Mutex
* pResMgrMutex
= NULL
;
62 static osl::Mutex
& getResMgrMutex()
66 osl::Guard
<osl::Mutex
> aGuard( *osl::Mutex::getGlobalMutex() );
68 pResMgrMutex
= new osl::Mutex();
78 friend class SimpleResMgr
;
79 friend class ResMgrContainer
;
81 ImpContent
* pContent
;
82 sal_uInt32 nOffCorrection
;
83 sal_uInt8
* pStringBlock
;
92 boost::unordered_map
<sal_uInt64
, int>* pResUseDump
;
94 InternalResMgr( const OUString
& rFileURL
,
95 const OUString
& aPrefix
,
96 const OUString
& aResName
,
97 const LanguageTag
& rLocale
);
101 bool IsGlobalAvailable( RESOURCE_TYPE nRT
, sal_uInt32 nId
) const;
102 void * LoadGlobalRes( RESOURCE_TYPE nRT
, sal_uInt32 nId
,
105 static void FreeGlobalRes( void *, void * );
108 class ResMgrContainer
110 static ResMgrContainer
* pOneInstance
;
112 struct ContainerElement
114 InternalResMgr
* pResMgr
;
126 boost::unordered_map
< OUString
, ContainerElement
, OUStringHash
> m_aResFiles
;
127 LanguageTag m_aDefLocale
;
129 ResMgrContainer() : m_aDefLocale( LANGUAGE_SYSTEM
) { init(); }
135 static ResMgrContainer
& get();
136 static void release();
138 InternalResMgr
* getResMgr( const OUString
& rPrefix
,
139 LanguageTag
& rLocale
,
140 bool bForceNewInstance
= false
142 InternalResMgr
* getNextFallback( InternalResMgr
* pResMgr
);
144 void freeResMgr( InternalResMgr
* pResMgr
);
146 void setDefLocale( const LanguageTag
& rLocale
)
147 { m_aDefLocale
= rLocale
; }
148 const LanguageTag
& getDefLocale() const
149 { return m_aDefLocale
; }
152 ResMgrContainer
* ResMgrContainer::pOneInstance
= NULL
;
154 ResMgrContainer
& ResMgrContainer::get()
157 pOneInstance
= new ResMgrContainer();
158 return *pOneInstance
;
161 ResMgrContainer::~ResMgrContainer()
163 for( boost::unordered_map
< OUString
, ContainerElement
, OUStringHash
>::iterator it
=
164 m_aResFiles
.begin(); it
!= m_aResFiles
.end(); ++it
)
166 OSL_TRACE( "Resource file %s loaded %d times",
167 OUStringToOString( it
->second
.aFileURL
, osl_getThreadTextEncoding() ).getStr(),
168 it
->second
.nLoadCount
);
169 delete it
->second
.pResMgr
;
173 void ResMgrContainer::release()
179 void ResMgrContainer::init()
181 assert( m_aResFiles
.empty() );
184 OUString
uri("$BRAND_BASE_DIR/" LIBO_SHARE_RESOURCE_FOLDER
"/");
185 rtl::Bootstrap::expandMacros(uri
); //TODO: detect failure
187 // collect all possible resource files
188 Directory
aDir( uri
);
189 if( aDir
.open() == FileBase::E_None
)
192 while( aDir
.getNextItem( aItem
) == FileBase::E_None
)
194 FileStatus
aStatus(osl_FileStatus_Mask_FileName
);
195 if( aItem
.getFileStatus( aStatus
) == FileBase::E_None
)
197 OUString aFileName
= aStatus
.getFileName();
198 if( ! aFileName
.endsWithIgnoreAsciiCase( ".res" ) )
200 OUString aResName
= aFileName
.copy( 0, aFileName
.getLength() - strlen(".res") );
201 if( aResName
.isEmpty() )
203 assert( m_aResFiles
.find( aResName
) == m_aResFiles
.end() );
204 m_aResFiles
[ aResName
].aFileURL
= uri
+ aFileName
;
207 "ResMgrContainer: " << aResName
<< " -> "
208 << m_aResFiles
[ aResName
].aFileURL
);
213 SAL_WARN( "tools.rc", "opening dir " << uri
<< " failed" );
215 // set default language
216 LanguageType nLang
= MsLangId::getSystemUILanguage();
217 m_aDefLocale
.reset( nLang
);
222 bool isAlreadyPureenUS(const LanguageTag
&rLocale
)
224 return ( rLocale
.getLanguageType() == LANGUAGE_ENGLISH_US
);
228 InternalResMgr
* ResMgrContainer::getResMgr( const OUString
& rPrefix
,
229 LanguageTag
& rLocale
,
230 bool bForceNewInstance
233 LanguageTag
aLocale( rLocale
);
234 boost::unordered_map
< OUString
, ContainerElement
, OUStringHash
>::iterator it
= m_aResFiles
.end();
236 ::std::vector
< OUString
> aFallbacks( aLocale
.getFallbackStrings( true));
237 if (!isAlreadyPureenUS( aLocale
))
238 aFallbacks
.push_back( "en-US"); // last resort if all fallbacks fail
240 for (::std::vector
< OUString
>::const_iterator
fb( aFallbacks
.begin()); fb
!= aFallbacks
.end(); ++fb
)
242 OUString
aSearch( rPrefix
+ *fb
);
243 it
= m_aResFiles
.find( aSearch
);
244 if( it
!= m_aResFiles
.end() )
246 // ensure InternalResMgr existance
247 if( ! it
->second
.pResMgr
)
249 InternalResMgr
* pImp
=
250 new InternalResMgr( it
->second
.aFileURL
, rPrefix
, it
->first
, aLocale
);
251 if( ! pImp
->Create() )
256 it
->second
.pResMgr
= pImp
;
261 // try if there is anything with this prefix at all
262 if( it
== m_aResFiles
.end() )
264 aLocale
.reset( LANGUAGE_SYSTEM
);
265 it
= m_aResFiles
.find( rPrefix
);
266 if( it
== m_aResFiles
.end() )
268 for( it
= m_aResFiles
.begin(); it
!= m_aResFiles
.end(); ++it
)
270 if( it
->first
.matchIgnoreAsciiCase( rPrefix
) )
272 // ensure InternalResMgr existance
273 if( ! it
->second
.pResMgr
)
275 InternalResMgr
* pImp
=
276 new InternalResMgr( it
->second
.aFileURL
,
280 if( ! pImp
->Create() )
285 it
->second
.pResMgr
= pImp
;
287 // try to guess locale
288 sal_Int32 nIndex
= rPrefix
.getLength();
289 if (nIndex
< it
->first
.getLength())
290 aLocale
.reset( it
->first
.copy( nIndex
));
293 SAL_WARN( "tools.rc", "ResMgrContainer::getResMgr: it->first " <<
294 it
->first
<< " shorter than prefix " << rPrefix
);
302 if( it
== m_aResFiles
.end() )
304 OUString sURL
= rPrefix
+ rLocale
.getBcp47() + ".res";
305 if ( m_aResFiles
.find(sURL
) == m_aResFiles
.end() )
307 m_aResFiles
[ sURL
].aFileURL
= sURL
;
308 return getResMgr(rPrefix
,rLocale
,bForceNewInstance
);
309 } // if ( m_aResFiles.find(sURL) == m_aResFiles.end() )
314 // at this point it->second.pResMgr must be filled either by creating a new one
315 // (then the refcount is still 0) or because we already had one
316 InternalResMgr
* pImp
= it
->second
.pResMgr
;
318 if( it
->second
.nRefCount
== 0 )
319 it
->second
.nLoadCount
++;
322 if( bForceNewInstance
)
324 if( it
->second
.nRefCount
== 0 )
326 // shortcut: the match algorithm already created the InternalResMgr
327 // take it instead of creating yet another one
328 it
->second
.pResMgr
= NULL
;
329 pImp
->bSingular
= true;
333 pImp
= new InternalResMgr( it
->second
.aFileURL
, rPrefix
, it
->first
, aLocale
);
334 pImp
->bSingular
= true;
335 if( !pImp
->Create() )
341 it
->second
.nLoadCount
++;
345 it
->second
.nRefCount
++;
350 InternalResMgr
* ResMgrContainer::getNextFallback( InternalResMgr
* pMgr
)
352 /* TODO-BCP47: this is nasty, but the previous code simply stripped a
353 * locale's variant and country in subsequent calls to end up with language
354 * only and then fallback to en-US if all failed, so this is at least
355 * equivalent if not better. Maybe this method could be changed to get
356 * passed / remember a fallback list and an index within to pick the next.
359 ::std::vector
< OUString
> aFallbacks( pMgr
->aLocale
.getFallbackStrings( true));
360 // The first is the locale itself, use next fallback or en-US.
361 /* TODO: what happens if the chain is "en-US", "en" -> "en-US", ...
362 * This was already an issue with the previous code. */
363 LanguageTag
aLocale( ((aFallbacks
.size() > 1) ? aFallbacks
[1] : OUString( "en-US")));
364 InternalResMgr
* pNext
= getResMgr( pMgr
->aPrefix
, aLocale
, pMgr
->bSingular
);
366 if( pNext
== pMgr
|| ( pNext
&& pNext
->aResName
.equals( pMgr
->aResName
) ) )
368 if( pNext
->bSingular
)
375 void ResMgrContainer::freeResMgr( InternalResMgr
* pResMgr
)
377 if( pResMgr
->bSingular
)
381 boost::unordered_map
< OUString
, ContainerElement
, OUStringHash
>::iterator it
=
382 m_aResFiles
.find( pResMgr
->aResName
);
383 if( it
!= m_aResFiles
.end() )
385 DBG_ASSERT( it
->second
.nRefCount
> 0, "InternalResMgr freed too often" );
386 if( it
->second
.nRefCount
> 0 )
387 it
->second
.nRefCount
--;
388 if( it
->second
.nRefCount
== 0 )
390 delete it
->second
.pResMgr
;
391 it
->second
.pResMgr
= NULL
;
397 void Resource::TestRes()
400 m_pResMgr
->TestStack( this );
405 sal_uInt64 nTypeAndId
;
409 struct ImpContentLessCompare
: public ::std::binary_function
< ImpContent
, ImpContent
, bool>
411 inline bool operator() (const ImpContent
& lhs
, const ImpContent
& rhs
) const
413 return lhs
.nTypeAndId
< rhs
.nTypeAndId
;
417 static ResHookProc pImplResHookProc
= 0;
419 InternalResMgr::InternalResMgr( const OUString
& rFileURL
,
420 const OUString
& rPrefix
,
421 const OUString
& rResName
,
422 const LanguageTag
& rLocale
)
424 , pStringBlock( NULL
)
426 , bEqual2Content( true )
428 , aFileName( rFileURL
)
430 , aResName( rResName
)
437 InternalResMgr::~InternalResMgr()
439 rtl_freeMemory(pContent
);
440 rtl_freeMemory(pStringBlock
);
446 const sal_Char
* pLogFile
= getenv( "STAR_RESOURCE_LOGGING" );
449 SvFileStream
aStm( OUString::createFromAscii( pLogFile
), STREAM_WRITE
);
450 aStm
.Seek( STREAM_SEEK_TO_END
);
451 OStringBuffer
aLine("FileName: ");
452 aLine
.append(OUStringToOString(aFileName
,
453 RTL_TEXTENCODING_UTF8
));
454 aStm
.WriteLine(aLine
.makeStringAndClear());
456 for( boost::unordered_map
<sal_uInt64
, int>::const_iterator it
= pResUseDump
->begin();
457 it
!= pResUseDump
->end(); ++it
)
459 sal_uInt64 nKeyId
= it
->first
;
460 aLine
.append("Type/Id: ");
461 aLine
.append(sal::static_int_cast
< sal_Int32
>((nKeyId
>> 32) & 0xFFFFFFFF));
463 aLine
.append(sal::static_int_cast
< sal_Int32
>(nKeyId
& 0xFFFFFFFF));
464 aStm
.WriteLine(aLine
.makeStringAndClear());
473 bool InternalResMgr::Create()
475 ResMgrContainer::get();
478 pStm
= new SvFileStream( aFileName
, (STREAM_READ
| STREAM_SHARE_DENYWRITE
| STREAM_NOCREATE
) );
479 if( pStm
->GetError() == 0 )
481 sal_Int32 lContLen
= 0;
483 pStm
->Seek( STREAM_SEEK_TO_END
);
485 if( ( pInternalResMgr->pHead = (RSHEADER_TYPE *)mmap( 0, nResourceFileSize,
486 PROT_READ, MAP_PRIVATE,
487 fRes, 0 ) ) != (RSHEADER_TYPE *)-1)
489 pStm
->SeekRel( - (int)sizeof( lContLen
) );
490 pStm
->Read( &lContLen
, sizeof( lContLen
) );
491 // is bigendian, swab to the right endian
492 lContLen
= ResMgr::GetLong( &lContLen
);
493 pStm
->SeekRel( -lContLen
);
494 // allocate stored ImpContent data (12 bytes per unit)
495 sal_uInt8
* pContentBuf
= (sal_uInt8
*)rtl_allocateMemory( lContLen
);
496 pStm
->Read( pContentBuf
, lContLen
);
497 // allocate ImpContent space (sizeof(ImpContent) per unit, not necessarily 12)
498 pContent
= (ImpContent
*)rtl_allocateMemory( sizeof(ImpContent
)*lContLen
/12 );
499 // Shorten to number of ImpContent
500 nEntries
= (sal_uInt32
)lContLen
/ 12;
501 bEqual2Content
= true;
506 const sal_Char
* pLogFile
= getenv( "STAR_RESOURCE_LOGGING" );
509 pResUseDump
= new boost::unordered_map
<sal_uInt64
, int>;
510 for( sal_uInt32 i
= 0; i
< nEntries
; ++i
)
511 (*pResUseDump
)[pContent
[i
].nTypeAndId
] = 1;
514 // swap the content to the right endian
515 pContent
[0].nTypeAndId
= ResMgr::GetUInt64( pContentBuf
);
516 pContent
[0].nOffset
= ResMgr::GetLong( pContentBuf
+8 );
517 sal_uInt32 nCount
= nEntries
- 1;
518 for( sal_uInt32 i
= 0,j
=1; i
< nCount
; ++i
,++j
)
520 // swap the content to the right endian
521 pContent
[j
].nTypeAndId
= ResMgr::GetUInt64( pContentBuf
+ (12*j
) );
522 pContent
[j
].nOffset
= ResMgr::GetLong( pContentBuf
+ (12*j
+8) );
523 if( pContent
[i
].nTypeAndId
>= pContent
[j
].nTypeAndId
)
525 if( (pContent
[i
].nTypeAndId
& 0xFFFFFFFF00000000LL
) == (pContent
[j
].nTypeAndId
& 0xFFFFFFFF00000000LL
)
526 && pContent
[i
].nOffset
>= pContent
[j
].nOffset
)
527 bEqual2Content
= false;
530 rtl_freeMemory( pContentBuf
);
531 OSL_ENSURE( bSorted
, "content not sorted" );
532 OSL_ENSURE( bEqual2Content
, "resource structure wrong" );
534 ::std::sort(pContent
,pContent
+nEntries
,ImpContentLessCompare());
535 // qsort( pContent, nEntries, sizeof( ImpContent ), Compare );
544 bool InternalResMgr::IsGlobalAvailable( RESOURCE_TYPE nRT
, sal_uInt32 nId
) const
546 // Anfang der Strings suchen
548 aValue
.nTypeAndId
= ((sal_uInt64(nRT
) << 32) | nId
);
549 ImpContent
* pFind
= ::std::lower_bound(pContent
,
552 ImpContentLessCompare());
553 return (pFind
!= (pContent
+ nEntries
)) && (pFind
->nTypeAndId
== aValue
.nTypeAndId
);
557 void* InternalResMgr::LoadGlobalRes( RESOURCE_TYPE nRT
, sal_uInt32 nId
,
562 pResUseDump
->erase( (sal_uInt64(nRT
) << 32) | nId
);
564 // search beginning of string
566 aValue
.nTypeAndId
= ((sal_uInt64(nRT
) << 32) | nId
);
567 ImpContent
* pEnd
= (pContent
+ nEntries
);
568 ImpContent
* pFind
= ::std::lower_bound( pContent
,
571 ImpContentLessCompare());
572 if( pFind
&& (pFind
!= pEnd
) && (pFind
->nTypeAndId
== aValue
.nTypeAndId
) )
574 if( nRT
== RSC_STRING
&& bEqual2Content
)
576 // string optimization
579 // search beginning of string
580 ImpContent
* pFirst
= pFind
;
581 ImpContent
* pLast
= pFirst
;
582 while( pFirst
> pContent
&& ((pFirst
-1)->nTypeAndId
>> 32) == RSC_STRING
)
584 while( pLast
< pEnd
&& (pLast
->nTypeAndId
>> 32) == RSC_STRING
)
586 nOffCorrection
= pFirst
->nOffset
;
589 pStm
->Seek( pLast
->nOffset
);
591 pStm
->Read( &aHdr
, sizeof( aHdr
) );
592 nSize
= pLast
->nOffset
+ aHdr
.GetGlobOff() - nOffCorrection
;
593 pStringBlock
= (sal_uInt8
*)rtl_allocateMemory( nSize
);
594 pStm
->Seek( pFirst
->nOffset
);
595 pStm
->Read( pStringBlock
, nSize
);
597 *pResHandle
= pStringBlock
;
598 return (sal_uInt8
*)pStringBlock
+ pFind
->nOffset
- nOffCorrection
;
599 } // if( nRT == RSC_STRING && bEqual2Content )
603 RSHEADER_TYPE aHeader
;
604 pStm
->Seek( pFind
->nOffset
);
605 pStm
->Read( &aHeader
, sizeof( RSHEADER_TYPE
) );
606 void * pRes
= rtl_allocateMemory( aHeader
.GetGlobOff() );
607 memcpy( pRes
, &aHeader
, sizeof( RSHEADER_TYPE
) );
608 pStm
->Read( (sal_uInt8
*)pRes
+ sizeof( RSHEADER_TYPE
),
609 aHeader
.GetGlobOff() - sizeof( RSHEADER_TYPE
) );
612 } // if( pFind && (pFind != pEnd) && (pFind->nTypeAndId == nValue) )
617 void InternalResMgr::FreeGlobalRes( void * pResHandle
, void * pResource
)
620 // Free allocated resource
621 rtl_freeMemory(pResource
);
626 OUString
GetTypeRes_Impl( const ResId
& rTypeId
)
628 // Return on resource errors
629 static int bInUse
= false;
630 OUString
aTypStr(OUString::number(rTypeId
.GetId()));
636 ResId
aResId( sal_uInt32(RSCVERSION_ID
), *rTypeId
.GetResMgr() );
637 aResId
.SetRT( RSC_VERSIONCONTROL
);
639 if ( rTypeId
.GetResMgr()->GetResource( aResId
) )
641 rTypeId
.SetRT( RSC_STRING
);
642 if ( rTypeId
.GetResMgr()->IsAvailable( rTypeId
) )
644 aTypStr
= rTypeId
.toString();
645 // Set class pointer to the end
646 rTypeId
.GetResMgr()->Increment( sizeof( RSHEADER_TYPE
) );
655 void ResMgr::RscError_Impl( const sal_Char
* pMessage
, ResMgr
* pResMgr
,
656 RESOURCE_TYPE nRT
, sal_uInt32 nId
,
657 std::vector
< ImpRCStack
>& rResStack
, int nDepth
)
659 // create a separate ResMgr with its own stack
660 // first get a second reference of the InternalResMgr
661 InternalResMgr
* pImp
=
662 ResMgrContainer::get().getResMgr( pResMgr
->pImpRes
->aPrefix
,
663 pResMgr
->pImpRes
->aLocale
,
666 ResMgr
* pNewResMgr
= new ResMgr( pImp
);
668 OStringBuffer
aStr(OUStringToOString(pResMgr
->GetFileName(),
669 RTL_TEXTENCODING_UTF8
));
671 if (aStr
.getLength())
674 aStr
.append("Class: ");
675 aStr
.append(OUStringToOString(GetTypeRes_Impl(ResId(nRT
, *pNewResMgr
)),
676 RTL_TEXTENCODING_UTF8
));
677 aStr
.append(", Id: ");
678 aStr
.append(static_cast<sal_Int32
>(nId
));
680 aStr
.append(pMessage
);
682 aStr
.append("\nResource Stack\n");
685 aStr
.append("Class: ");
686 aStr
.append(OUStringToOString(GetTypeRes_Impl(
687 ResId(rResStack
[nDepth
].pResource
->GetRT(), *pNewResMgr
)),
688 RTL_TEXTENCODING_UTF8
));
689 aStr
.append(", Id: ");
690 aStr
.append(static_cast<sal_Int32
>(
691 rResStack
[nDepth
].pResource
->GetId()));
698 OSL_FAIL(aStr
.getStr());
703 static void RscException_Impl()
705 switch ( osl_raiseSignal( OSL_SIGNAL_USER_RESOURCEFAILURE
, (void*)"" ) )
707 case osl_Signal_ActCallNextHdl
:
710 case osl_Signal_ActIgnore
:
713 case osl_Signal_ActAbortApp
:
717 case osl_Signal_ActKillApp
:
722 void ImpRCStack::Init( ResMgr
* pMgr
, const Resource
* pObj
, sal_uInt32 Id
)
729 nId
= Id
& ~RSC_DONTRELEASE
; //TLX: Besser Init aendern
731 if ( !(Id
& RSC_DONTRELEASE
) )
732 Flags
|= RC_AUTORELEASE
;
735 void ImpRCStack::Clear()
746 static RSHEADER_TYPE
* LocalResource( const ImpRCStack
* pStack
,
747 RESOURCE_TYPE nRTType
,
750 // Returns position of the resource if found or NULL otherwise
751 RSHEADER_TYPE
* pTmp
; // Pointer to child resource
752 RSHEADER_TYPE
* pEnd
; // Pointer to the end of this resource
754 if ( pStack
->pResource
&& pStack
->pClassRes
)
756 pTmp
= (RSHEADER_TYPE
*)
757 ((sal_uInt8
*)pStack
->pResource
+ pStack
->pResource
->GetLocalOff());
758 pEnd
= (RSHEADER_TYPE
*)
759 ((sal_uInt8
*)pStack
->pResource
+ pStack
->pResource
->GetGlobOff());
760 while ( pTmp
!= pEnd
)
762 if ( pTmp
->GetRT() == nRTType
&& pTmp
->GetId() == nId
)
764 pTmp
= (RSHEADER_TYPE
*)((sal_uInt8
*)pTmp
+ pTmp
->GetGlobOff());
771 void* ResMgr::pEmptyBuffer
= NULL
;
773 void* ResMgr::getEmptyBuffer()
776 pEmptyBuffer
= rtl_allocateZeroMemory( 1024 );
780 void ResMgr::DestroyAllResMgr()
783 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
786 rtl_freeMemory( pEmptyBuffer
);
789 ResMgrContainer::release();
795 void ResMgr::Init( const OUString
& rFileName
)
797 (void) rFileName
; // avoid warning about unused parameter
798 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
803 OStringBuffer
aStr("Resourcefile not found:\n");
804 aStr
.append(OUStringToOString(rFileName
, RTL_TEXTENCODING_UTF8
));
805 OSL_FAIL(aStr
.getStr());
812 void* aResHandle
= 0; // Helper variable for resource handles
813 void* pVoid
; // Pointer on the resource
815 pVoid
= pImpRes
->LoadGlobalRes( RSC_VERSIONCONTROL
, RSCVERSION_ID
,
818 InternalResMgr::FreeGlobalRes( aResHandle
, pVoid
);
821 SAL_WARN("tools.rc", "Wrong version: " << pImpRes
->aFileName
);
827 pFallbackResMgr
= pOriginalResMgr
= NULL
;
831 ResMgr::ResMgr( InternalResMgr
* pImpMgr
)
834 Init( pImpMgr
->aFileName
);
839 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
841 ResMgrContainer::get().freeResMgr( pImpRes
);
843 // clean up possible left rc stack frames
844 while( nCurStack
> 0 )
846 if( ( aStack
[nCurStack
].Flags
& (RC_GLOBAL
| RC_NOTFOUND
) ) == RC_GLOBAL
)
847 InternalResMgr::FreeGlobalRes( aStack
[nCurStack
].aResHandle
,
848 aStack
[nCurStack
].pResource
);
853 void ResMgr::incStack()
856 if( nCurStack
>= int(aStack
.size()) )
857 aStack
.push_back( ImpRCStack() );
858 aStack
[nCurStack
].Clear();
860 DBG_ASSERT( nCurStack
< 32, "Resource stack unreasonably large" );
863 void ResMgr::decStack()
865 DBG_ASSERT( nCurStack
> 0, "resource stack underrun !" );
866 if( (aStack
[nCurStack
].Flags
& RC_FALLBACK_UP
) )
869 // warning: this will delete *this, see below
870 pOriginalResMgr
->decStack();
874 ImpRCStack
& rTop
= aStack
[nCurStack
];
875 if( (rTop
.Flags
& RC_FALLBACK_DOWN
) )
877 #if OSL_DEBUG_LEVEL > 1
878 OSL_TRACE( "returning from fallback %s",
879 OUStringToOString(pFallbackResMgr
->GetFileName(), osl_getThreadTextEncoding() ).getStr() );
881 delete pFallbackResMgr
;
882 pFallbackResMgr
= NULL
;
890 void ResMgr::TestStack( const Resource
* pResObj
)
892 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
894 int upperLimit
= nCurStack
;
896 if ( upperLimit
< 0 )
898 OSL_FAIL( "resource stack underrun!" );
899 upperLimit
= aStack
.size() - 1;
901 else if ( upperLimit
>= static_cast<int>(aStack
.size()) )
903 OSL_FAIL( "stack occupation index > allocated stack size" );
904 upperLimit
= aStack
.size() - 1;
907 if ( DbgIsResource() )
909 for( int i
= 1; i
<= upperLimit
; ++i
)
911 if ( aStack
[i
].pResObj
== pResObj
)
913 RscError_Impl( "Resource not freed! ", this,
914 aStack
[i
].pResource
->GetRT(),
915 aStack
[i
].pResource
->GetId(),
924 void ResMgr::TestStack( const Resource
* )
930 bool ResMgr::IsAvailable( const ResId
& rId
, const Resource
* pResObj
) const
932 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
934 bool bAvailable
= false;
935 RSHEADER_TYPE
* pClassRes
= rId
.GetpResource();
936 RESOURCE_TYPE nRT
= rId
.GetRT2();
937 sal_uInt32 nId
= rId
.GetId();
938 const ResMgr
* pMgr
= rId
.GetResMgr();
943 if( pMgr
->pFallbackResMgr
)
946 aId
.SetResMgr( NULL
);
947 return pMgr
->pFallbackResMgr
->IsAvailable( aId
, pResObj
);
950 if ( !pResObj
|| pResObj
== pMgr
->aStack
[pMgr
->nCurStack
].pResObj
)
953 pClassRes
= LocalResource( &pMgr
->aStack
[pMgr
->nCurStack
], nRT
, nId
);
956 if ( pClassRes
->GetRT() == nRT
)
962 bAvailable
= pMgr
->pImpRes
->IsGlobalAvailable( nRT
, nId
);
967 void* ResMgr::GetClass()
969 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
971 if( pFallbackResMgr
)
972 return pFallbackResMgr
->GetClass();
974 return aStack
[nCurStack
].pClassRes
;
977 bool ResMgr::GetResource( const ResId
& rId
, const Resource
* pResObj
)
979 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
981 if( pFallbackResMgr
)
984 aId
.SetResMgr( NULL
);
985 return pFallbackResMgr
->GetResource( aId
, pResObj
);
988 ResMgr
* pMgr
= rId
.GetResMgr();
989 if ( pMgr
&& (this != pMgr
) )
990 return pMgr
->GetResource( rId
, pResObj
);
992 // normally Increment will pop the context; this is
993 // not possible in RC_NOTFOUND case, so pop a frame here
994 ImpRCStack
* pTop
= &aStack
[nCurStack
];
995 if( (pTop
->Flags
& RC_NOTFOUND
) )
1000 RSHEADER_TYPE
* pClassRes
= rId
.GetpResource();
1001 RESOURCE_TYPE nRT
= rId
.GetRT2();
1002 sal_uInt32 nId
= rId
.GetId();
1005 pTop
= &aStack
[nCurStack
];
1006 pTop
->Init( pMgr
, pResObj
, nId
|
1007 (rId
.IsAutoRelease() ? 0 : RSC_DONTRELEASE
) );
1011 if ( pClassRes
->GetRT() == nRT
)
1012 pTop
->pClassRes
= pClassRes
;
1016 RscError_Impl( "Different class and resource type!",
1017 this, nRT
, nId
, aStack
, nCurStack
-1 );
1019 pTop
->Flags
|= RC_NOTFOUND
;
1020 pTop
->pClassRes
= getEmptyBuffer();
1021 pTop
->pResource
= (RSHEADER_TYPE
*)pTop
->pClassRes
;
1027 OSL_ENSURE( nCurStack
> 0, "stack of 1 to shallow" );
1028 pTop
->pClassRes
= LocalResource( &aStack
[nCurStack
-1], nRT
, nId
);
1031 if ( pTop
->pClassRes
)
1032 // lokale Resource, nicht system Resource
1033 pTop
->pResource
= (RSHEADER_TYPE
*)pTop
->pClassRes
;
1036 pTop
->pClassRes
= pImpRes
->LoadGlobalRes( nRT
, nId
, &pTop
->aResHandle
);
1037 if ( pTop
->pClassRes
)
1039 pTop
->Flags
|= RC_GLOBAL
;
1040 pTop
->pResource
= (RSHEADER_TYPE
*)pTop
->pClassRes
;
1044 // try to get a fallback resource
1045 pFallbackResMgr
= CreateFallbackResMgr( rId
, pResObj
);
1046 if( pFallbackResMgr
)
1048 pTop
->Flags
|= RC_FALLBACK_DOWN
;
1050 OStringBuffer
aMess("found resource ");
1051 aMess
.append(static_cast<sal_Int32
>(nId
));
1052 aMess
.append(" in fallback ");
1053 aMess
.append(OUStringToOString(
1054 pFallbackResMgr
->GetFileName(),
1055 osl_getThreadTextEncoding()));
1057 RscError_Impl(aMess
.getStr(),
1058 this, nRT
, nId
, aStack
, nCurStack
-1);
1064 RscError_Impl( "Cannot load resource! ",
1065 this, nRT
, nId
, aStack
, nCurStack
-1 );
1067 pTop
->Flags
|= RC_NOTFOUND
;
1068 pTop
->pClassRes
= getEmptyBuffer();
1069 pTop
->pResource
= (RSHEADER_TYPE
*)pTop
->pClassRes
;
1078 void * ResMgr::GetResourceSkipHeader( const ResId
& rResId
, ResMgr
** ppResMgr
)
1080 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1082 DBG_ASSERT( rResId
.GetResMgr(), "illegal ResId without ResMgr" );
1083 *ppResMgr
= rResId
.GetResMgr();
1086 (*ppResMgr
)->GetResource( rResId
);
1087 (*ppResMgr
)->Increment( sizeof( RSHEADER_TYPE
) );
1088 return (*ppResMgr
)->GetClass();
1090 return getEmptyBuffer();
1093 void ResMgr::PopContext( const Resource
* pResObj
)
1095 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1097 if( pFallbackResMgr
)
1099 pFallbackResMgr
->PopContext( pResObj
);
1104 if ( DbgIsResource() )
1106 if ( (aStack
[nCurStack
].pResObj
!= pResObj
) || nCurStack
== 0 )
1108 RscError_Impl( "Cannot free resource! ", this,
1109 RSC_NOTYPE
, 0, aStack
, nCurStack
);
1114 if ( nCurStack
> 0 )
1116 ImpRCStack
* pTop
= &aStack
[nCurStack
];
1118 if ( DbgIsResource() && !(pTop
->Flags
& RC_NOTFOUND
) )
1120 void* pRes
= (sal_uInt8
*)pTop
->pResource
+
1121 pTop
->pResource
->GetLocalOff();
1123 if ( pTop
->pClassRes
!= pRes
)
1125 RscError_Impl( "Classpointer not at the end!",
1126 this, pTop
->pResource
->GetRT(),
1127 pTop
->pResource
->GetId(),
1128 aStack
, nCurStack
-1 );
1134 if( (pTop
->Flags
& (RC_GLOBAL
| RC_NOTFOUND
)) == RC_GLOBAL
)
1135 // free global resource if resource is foreign
1136 InternalResMgr::FreeGlobalRes( pTop
->aResHandle
, pTop
->pResource
);
1141 RSHEADER_TYPE
* ResMgr::CreateBlock( const ResId
& rId
)
1143 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1145 if( pFallbackResMgr
)
1148 aId
.SetResMgr( NULL
);
1149 return pFallbackResMgr
->CreateBlock( aId
);
1152 RSHEADER_TYPE
* pHeader
= NULL
;
1153 if ( GetResource( rId
) )
1155 // Pointer is at the beginning of the resource, thus
1156 // class pointer points to the header, and the remaining size
1157 // equals to total size of allocated memory
1158 pHeader
= (RSHEADER_TYPE
*)rtl_allocateMemory( GetRemainSize() );
1159 memcpy( pHeader
, GetClass(), GetRemainSize() );
1160 Increment( pHeader
->GetLocalOff() ); //ans Ende setzen
1161 if ( pHeader
->GetLocalOff() != pHeader
->GetGlobOff() )
1162 // Has sub-resources, thus release them as well
1169 sal_Int16
ResMgr::GetShort( void * pShort
)
1171 return ((*((sal_uInt8
*)pShort
+ 0) << 8) |
1172 (*((sal_uInt8
*)pShort
+ 1) << 0) );
1175 sal_Int32
ResMgr::GetLong( void * pLong
)
1177 return ((*((sal_uInt8
*)pLong
+ 0) << 24) |
1178 (*((sal_uInt8
*)pLong
+ 1) << 16) |
1179 (*((sal_uInt8
*)pLong
+ 2) << 8) |
1180 (*((sal_uInt8
*)pLong
+ 3) << 0) );
1183 sal_uInt64
ResMgr::GetUInt64( void* pDatum
)
1185 return ((sal_uInt64(*((sal_uInt8
*)pDatum
+ 0)) << 56) |
1186 (sal_uInt64(*((sal_uInt8
*)pDatum
+ 1)) << 48) |
1187 (sal_uInt64(*((sal_uInt8
*)pDatum
+ 2)) << 40) |
1188 (sal_uInt64(*((sal_uInt8
*)pDatum
+ 3)) << 32) |
1189 (sal_uInt64(*((sal_uInt8
*)pDatum
+ 4)) << 24) |
1190 (sal_uInt64(*((sal_uInt8
*)pDatum
+ 5)) << 16) |
1191 (sal_uInt64(*((sal_uInt8
*)pDatum
+ 6)) << 8) |
1192 (sal_uInt64(*((sal_uInt8
*)pDatum
+ 7)) << 0) );
1195 sal_uInt32
ResMgr::GetStringWithoutHook( OUString
& rStr
, const sal_uInt8
* pStr
)
1198 sal_uInt32 nRet
= GetStringSize( pStr
, nLen
);
1199 const sal_Char
* str
= reinterpret_cast< const sal_Char
* >( pStr
);
1200 OUString
aString( str
, strlen( str
), RTL_TEXTENCODING_UTF8
,
1201 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_MAPTOPRIVATE
|
1202 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT
|
1203 RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT
);
1208 sal_uInt32
ResMgr::GetString( OUString
& rStr
, const sal_uInt8
* pStr
)
1211 sal_uInt32 nRet
= GetStringWithoutHook( aString
, pStr
);
1212 if ( pImplResHookProc
)
1213 aString
= pImplResHookProc( aString
);
1218 sal_uInt32
ResMgr::GetByteString( OString
& rStr
, const sal_uInt8
* pStr
)
1221 sal_uInt32 nRet
= GetStringSize( pStr
, nLen
);
1222 rStr
= OString( (const sal_Char
*)pStr
, nLen
);
1226 sal_uInt32
ResMgr::GetStringSize( const sal_uInt8
* pStr
, sal_uInt32
& nLen
)
1228 nLen
= static_cast< sal_uInt32
>( strlen( (const char*)pStr
) );
1229 return GetStringSize( nLen
);
1232 sal_uInt32
ResMgr::GetRemainSize()
1234 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1236 if( pFallbackResMgr
)
1237 return pFallbackResMgr
->GetRemainSize();
1239 const ImpRCStack
& rTop
= aStack
[nCurStack
];
1240 return (sal_uInt32
)((sal_IntPtr
)(sal_uInt8
*)rTop
.pResource
+
1241 rTop
.pResource
->GetLocalOff() -
1242 (sal_IntPtr
)(sal_uInt8
*)rTop
.pClassRes
);
1245 void* ResMgr::Increment( sal_uInt32 nSize
)
1247 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1249 if( pFallbackResMgr
)
1250 return pFallbackResMgr
->Increment( nSize
);
1252 ImpRCStack
& rStack
= aStack
[nCurStack
];
1253 if( (rStack
.Flags
& RC_NOTFOUND
) )
1254 return rStack
.pClassRes
;
1256 sal_uInt8
* pClassRes
= (sal_uInt8
*)rStack
.pClassRes
+ nSize
;
1258 rStack
.pClassRes
= pClassRes
;
1260 RSHEADER_TYPE
* pRes
= rStack
.pResource
;
1262 sal_uInt32 nLocalOff
= pRes
->GetLocalOff();
1263 if ( (pRes
->GetGlobOff() == nLocalOff
) &&
1264 (((char*)pRes
+ nLocalOff
) == rStack
.pClassRes
) &&
1265 (rStack
.Flags
& RC_AUTORELEASE
))
1267 PopContext( rStack
.pResObj
);
1273 ResMgr
* ResMgr::CreateFallbackResMgr( const ResId
& rId
, const Resource
* pResource
)
1275 ResMgr
*pFallback
= NULL
;
1278 // get the next fallback level in resource file scope
1279 InternalResMgr
* pRes
= ResMgrContainer::get().getNextFallback( pImpRes
);
1282 // check that the fallback locale is not already in the chain of
1283 // fallbacks - prevent fallback loops
1284 ResMgr
* pResMgr
= this;
1285 while( pResMgr
&& (pResMgr
->pImpRes
->aLocale
!= pRes
->aLocale
))
1287 pResMgr
= pResMgr
->pOriginalResMgr
;
1291 // found a recursion, no fallback possible
1292 ResMgrContainer::get().freeResMgr( pRes
);
1295 OSL_TRACE( "trying fallback: %s", OUStringToOString( pRes
->aFileName
, osl_getThreadTextEncoding() ).getStr() );
1296 pFallback
= new ResMgr( pRes
);
1297 pFallback
->pOriginalResMgr
= this;
1298 // try to recreate the resource stack
1299 bool bHaveStack
= true;
1300 for( int i
= 1; i
< nCurStack
; i
++ )
1302 if( !aStack
[i
].pResource
)
1307 ResId
aId( aStack
[i
].pResource
->GetId(), *pFallbackResMgr
);
1308 aId
.SetRT( aStack
[i
].pResource
->GetRT() );
1309 if( !pFallback
->GetResource( aId
) )
1317 ResId
aId( rId
.GetId(), *pFallback
);
1318 aId
.SetRT( rId
.GetRT() );
1319 if( !pFallback
->GetResource( aId
, pResource
) )
1322 pFallback
->aStack
[pFallback
->nCurStack
].Flags
|= RC_FALLBACK_UP
;
1334 // method left here for SDK compatibility,
1335 // used in "framework/source/services/substitutepathvars.cxx"
1336 // phone numbers no longer in use for resource files
1338 const char* ResMgr::GetLang( LanguageType
& nType
, sal_uInt16 nPrio
)
1340 if ( nType
== LANGUAGE_SYSTEM
|| nType
== LANGUAGE_DONTKNOW
)
1341 nType
= MsLangId::getSystemUILanguage();
1347 case LANGUAGE_DANISH
:
1350 case LANGUAGE_DUTCH
:
1351 case LANGUAGE_DUTCH_BELGIAN
:
1354 case LANGUAGE_ENGLISH
:
1355 case LANGUAGE_ENGLISH_UK
:
1356 case LANGUAGE_ENGLISH_EIRE
:
1357 case LANGUAGE_ENGLISH_SAFRICA
:
1358 case LANGUAGE_ENGLISH_JAMAICA
:
1359 case LANGUAGE_ENGLISH_BELIZE
:
1360 case LANGUAGE_ENGLISH_TRINIDAD
:
1361 case LANGUAGE_ENGLISH_ZIMBABWE
:
1362 case LANGUAGE_ENGLISH_PHILIPPINES
:
1365 case LANGUAGE_ENGLISH_US
:
1366 case LANGUAGE_ENGLISH_CAN
:
1369 case LANGUAGE_ENGLISH_AUS
:
1370 case LANGUAGE_ENGLISH_NZ
:
1372 case LANGUAGE_ESTONIAN
:
1376 case LANGUAGE_FINNISH
:
1379 case LANGUAGE_FRENCH_CANADIAN
:
1382 case LANGUAGE_FRENCH
:
1383 case LANGUAGE_FRENCH_BELGIAN
:
1384 case LANGUAGE_FRENCH_SWISS
:
1385 case LANGUAGE_FRENCH_LUXEMBOURG
:
1386 case LANGUAGE_FRENCH_MONACO
:
1389 case LANGUAGE_GERMAN
:
1390 case LANGUAGE_GERMAN_SWISS
:
1391 case LANGUAGE_GERMAN_AUSTRIAN
:
1392 case LANGUAGE_GERMAN_LUXEMBOURG
:
1393 case LANGUAGE_GERMAN_LIECHTENSTEIN
:
1396 case LANGUAGE_ITALIAN
:
1397 case LANGUAGE_ITALIAN_SWISS
:
1400 case LANGUAGE_NORWEGIAN
:
1401 case LANGUAGE_NORWEGIAN_BOKMAL
:
1404 case LANGUAGE_PORTUGUESE
:
1407 case LANGUAGE_PORTUGUESE_BRAZILIAN
:
1410 case LANGUAGE_SPANISH_DATED
:
1411 case LANGUAGE_SPANISH_MEXICAN
:
1412 case LANGUAGE_SPANISH_MODERN
:
1413 case LANGUAGE_SPANISH_GUATEMALA
:
1414 case LANGUAGE_SPANISH_COSTARICA
:
1415 case LANGUAGE_SPANISH_PANAMA
:
1416 case LANGUAGE_SPANISH_DOMINICAN_REPUBLIC
:
1417 case LANGUAGE_SPANISH_VENEZUELA
:
1418 case LANGUAGE_SPANISH_COLOMBIA
:
1419 case LANGUAGE_SPANISH_PERU
:
1420 case LANGUAGE_SPANISH_ARGENTINA
:
1421 case LANGUAGE_SPANISH_ECUADOR
:
1422 case LANGUAGE_SPANISH_CHILE
:
1423 case LANGUAGE_SPANISH_URUGUAY
:
1424 case LANGUAGE_SPANISH_PARAGUAY
:
1425 case LANGUAGE_SPANISH_BOLIVIA
:
1428 case LANGUAGE_SWEDISH
:
1431 case LANGUAGE_POLISH
:
1433 case LANGUAGE_CZECH
:
1435 case LANGUAGE_SLOVENIAN
:
1437 case LANGUAGE_HUNGARIAN
:
1439 case LANGUAGE_RUSSIAN
:
1441 case LANGUAGE_SLOVAK
:
1443 case LANGUAGE_GREEK
:
1445 case LANGUAGE_TURKISH
:
1448 case LANGUAGE_CHINESE_SIMPLIFIED
:
1450 case LANGUAGE_CHINESE_TRADITIONAL
:
1452 case LANGUAGE_JAPANESE
:
1454 case LANGUAGE_KOREAN
:
1455 case LANGUAGE_KOREAN_JOHAB
:
1459 case LANGUAGE_HINDI
:
1462 case LANGUAGE_ARABIC_PRIMARY_ONLY
:
1463 case LANGUAGE_ARABIC_IRAQ
:
1464 case LANGUAGE_ARABIC_EGYPT
:
1465 case LANGUAGE_ARABIC_LIBYA
:
1466 case LANGUAGE_ARABIC_ALGERIA
:
1467 case LANGUAGE_ARABIC_MOROCCO
:
1468 case LANGUAGE_ARABIC_TUNISIA
:
1469 case LANGUAGE_ARABIC_OMAN
:
1470 case LANGUAGE_ARABIC_YEMEN
:
1471 case LANGUAGE_ARABIC_SYRIA
:
1472 case LANGUAGE_ARABIC_JORDAN
:
1473 case LANGUAGE_ARABIC_LEBANON
:
1474 case LANGUAGE_ARABIC_KUWAIT
:
1475 case LANGUAGE_ARABIC_UAE
:
1476 case LANGUAGE_ARABIC_BAHRAIN
:
1477 case LANGUAGE_ARABIC_QATAR
:
1480 case LANGUAGE_HEBREW
:
1483 case LANGUAGE_CATALAN
:
1490 else if ( nPrio
== 1 )
1494 case LANGUAGE_FRENCH_CANADIAN
:
1497 case LANGUAGE_PORTUGUESE_BRAZILIAN
:
1504 else if ( nPrio
== 2 )
1506 else if ( nPrio
== 3 )
1508 else if ( nPrio
== 4 )
1514 ResMgr
* ResMgr::CreateResMgr( const sal_Char
* pPrefixName
,
1515 LanguageTag aLocale
)
1517 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1519 OUString
aPrefix( pPrefixName
, strlen( pPrefixName
), osl_getThreadTextEncoding() );
1521 if( aLocale
.isSystemLocale() )
1522 aLocale
= ResMgrContainer::get().getDefLocale();
1524 InternalResMgr
* pImp
= ResMgrContainer::get().getResMgr( aPrefix
, aLocale
);
1525 return pImp
? new ResMgr( pImp
) : NULL
;
1528 ResMgr
* ResMgr::SearchCreateResMgr(
1529 const sal_Char
* pPrefixName
,
1530 LanguageTag
& rLocale
)
1532 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1534 OUString
aPrefix( pPrefixName
, strlen( pPrefixName
), osl_getThreadTextEncoding() );
1536 if( rLocale
.isSystemLocale() )
1537 rLocale
= ResMgrContainer::get().getDefLocale();
1539 InternalResMgr
* pImp
= ResMgrContainer::get().getResMgr( aPrefix
, rLocale
);
1540 return pImp
? new ResMgr( pImp
) : NULL
;
1543 sal_Int16
ResMgr::ReadShort()
1545 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1547 if( pFallbackResMgr
)
1548 return pFallbackResMgr
->ReadShort();
1550 sal_Int16 n
= GetShort( GetClass() );
1551 Increment( sizeof( sal_Int16
) );
1555 sal_Int32
ResMgr::ReadLong()
1557 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1559 if( pFallbackResMgr
)
1560 return pFallbackResMgr
->ReadLong();
1562 sal_Int32 n
= GetLong( GetClass() );
1563 Increment( sizeof( sal_Int32
) );
1567 OUString
ResMgr::ReadStringWithoutHook()
1569 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1571 if( pFallbackResMgr
)
1572 return pFallbackResMgr
->ReadStringWithoutHook();
1576 const ImpRCStack
& rTop
= aStack
[nCurStack
];
1577 if( (rTop
.Flags
& RC_NOTFOUND
) )
1579 #if OSL_DEBUG_LEVEL > 0
1580 aRet
= "<resource not found>";
1584 Increment( GetStringWithoutHook( aRet
, (const sal_uInt8
*)GetClass() ) );
1589 OUString
ResMgr::ReadString()
1591 OUString aRet
= ReadStringWithoutHook();
1592 if ( pImplResHookProc
)
1593 aRet
= pImplResHookProc( aRet
);
1597 OString
ResMgr::ReadByteString()
1599 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1601 if( pFallbackResMgr
)
1602 return pFallbackResMgr
->ReadByteString();
1606 const ImpRCStack
& rTop
= aStack
[nCurStack
];
1607 if( (rTop
.Flags
& RC_NOTFOUND
) )
1609 #if OSL_DEBUG_LEVEL > 0
1610 aRet
= OString( "<resource not found>" );
1614 Increment( GetByteString( aRet
, (const sal_uInt8
*)GetClass() ) );
1619 OString
ResMgr::GetAutoHelpId()
1621 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1623 if( pFallbackResMgr
)
1624 return pFallbackResMgr
->GetAutoHelpId();
1626 OSL_ENSURE( nCurStack
, "resource stack empty in Auto help id generation" );
1627 if( nCurStack
< 1 || nCurStack
> 2 )
1630 // prepare HID, start with resource prefix
1631 OStringBuffer
aHID( 32 );
1632 aHID
.append( OUStringToOString( pImpRes
->aPrefix
, RTL_TEXTENCODING_UTF8
) );
1636 const ImpRCStack
*pRC
= StackTop();
1637 OSL_ENSURE( pRC
, "missing resource stack level" );
1639 if ( nCurStack
== 1 )
1641 // auto help ids for top level windows
1642 switch( pRC
->pResource
->GetRT() ) {
1643 case RSC_DOCKINGWINDOW
: aHID
.append( "DockingWindow" ); break;
1644 case RSC_WORKWIN
: aHID
.append( "WorkWindow" ); break;
1645 case RSC_MODELESSDIALOG
: aHID
.append( "ModelessDialog" ); break;
1646 case RSC_FLOATINGWINDOW
: aHID
.append( "FloatingWindow" ); break;
1647 case RSC_MODALDIALOG
: aHID
.append( "ModalDialog" ); break;
1648 case RSC_TABPAGE
: aHID
.append( "TabPage" ); break;
1649 default: return OString();
1654 // only controls with the following parents get auto help ids
1655 const ImpRCStack
*pRC1
= StackTop(1);
1656 switch( pRC1
->pResource
->GetRT() ) {
1657 case RSC_DOCKINGWINDOW
:
1659 case RSC_MODELESSDIALOG
:
1660 case RSC_FLOATINGWINDOW
:
1661 case RSC_MODALDIALOG
:
1663 // intentionally no breaks!
1664 // auto help ids for controls
1665 switch( pRC
->pResource
->GetRT() ) {
1666 case RSC_TABCONTROL
: aHID
.append( "TabControl" ); break;
1667 case RSC_RADIOBUTTON
: aHID
.append( "RadioButton" ); break;
1668 case RSC_CHECKBOX
: aHID
.append( "CheckBox" ); break;
1669 case RSC_TRISTATEBOX
: aHID
.append( "TriStateBox" ); break;
1670 case RSC_EDIT
: aHID
.append( "Edit" ); break;
1671 case RSC_MULTILINEEDIT
: aHID
.append( "MultiLineEdit" ); break;
1672 case RSC_MULTILISTBOX
: aHID
.append( "MultiListBox" ); break;
1673 case RSC_LISTBOX
: aHID
.append( "ListBox" ); break;
1674 case RSC_COMBOBOX
: aHID
.append( "ComboBox" ); break;
1675 case RSC_PUSHBUTTON
: aHID
.append( "PushButton" ); break;
1676 case RSC_SPINFIELD
: aHID
.append( "SpinField" ); break;
1677 case RSC_PATTERNFIELD
: aHID
.append( "PatternField" ); break;
1678 case RSC_NUMERICFIELD
: aHID
.append( "NumericField" ); break;
1679 case RSC_METRICFIELD
: aHID
.append( "MetricField" ); break;
1680 case RSC_CURRENCYFIELD
: aHID
.append( "CurrencyField" ); break;
1681 case RSC_DATEFIELD
: aHID
.append( "DateField" ); break;
1682 case RSC_TIMEFIELD
: aHID
.append( "TimeField" ); break;
1683 case RSC_NUMERICBOX
: aHID
.append( "NumericBox" ); break;
1684 case RSC_METRICBOX
: aHID
.append( "MetricBox" ); break;
1685 case RSC_CURRENCYBOX
: aHID
.append( "CurrencyBox" ); break;
1686 case RSC_DATEBOX
: aHID
.append( "DateBox" ); break;
1687 case RSC_TIMEBOX
: aHID
.append( "TimeBox" ); break;
1688 case RSC_IMAGEBUTTON
: aHID
.append( "ImageButton" ); break;
1689 case RSC_MENUBUTTON
: aHID
.append( "MenuButton" ); break;
1690 case RSC_MOREBUTTON
: aHID
.append( "MoreButton" ); break;
1692 // no type, no auto HID
1701 // append resource id hierarchy
1702 for( int nOff
= nCurStack
-1; nOff
>= 0; nOff
-- )
1705 pRC
= StackTop( nOff
);
1707 OSL_ENSURE( pRC
->pResource
, "missing resource in resource stack level !" );
1708 if( pRC
->pResource
)
1709 aHID
.append( sal_Int32( pRC
->pResource
->GetId() ) );
1712 return aHID
.makeStringAndClear();
1715 void ResMgr::SetReadStringHook( ResHookProc pProc
)
1717 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1718 pImplResHookProc
= pProc
;
1721 ResHookProc
ResMgr::GetReadStringHook()
1723 return pImplResHookProc
;
1726 void ResMgr::SetDefaultLocale( const LanguageTag
& rLocale
)
1728 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1729 ResMgrContainer::get().setDefLocale( rLocale
);
1732 const OUString
& ResMgr::GetFileName() const
1734 return pImpRes
->aFileName
;
1737 SimpleResMgr::SimpleResMgr( const sal_Char
* pPrefixName
,
1738 const LanguageTag
& rLocale
)
1740 OUString
aPrefix( pPrefixName
, strlen( pPrefixName
), osl_getThreadTextEncoding() );
1741 LanguageTag
aLocale( rLocale
);
1743 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1744 if( aLocale
.isSystemLocale() )
1745 aLocale
= ResMgrContainer::get().getDefLocale();
1747 m_pResImpl
= ResMgrContainer::get().getResMgr( aPrefix
, aLocale
, true );
1748 DBG_ASSERT( m_pResImpl
, "SimpleResMgr::SimpleResMgr : have no impl class !" );
1751 SimpleResMgr::~SimpleResMgr()
1756 SimpleResMgr
* SimpleResMgr::Create( const sal_Char
* pPrefixName
, LanguageTag aLocale
)
1758 return new SimpleResMgr( pPrefixName
, aLocale
);
1761 bool SimpleResMgr::IsAvailable( RESOURCE_TYPE _resourceType
, sal_uInt32 _resourceId
)
1763 osl::MutexGuard
aGuard(m_aAccessSafety
);
1765 if ( ( RSC_STRING
!= _resourceType
) && ( RSC_RESOURCE
!= _resourceType
) )
1768 DBG_ASSERT( m_pResImpl
, "SimpleResMgr::IsAvailable: have no impl class !" );
1769 return m_pResImpl
->IsGlobalAvailable( _resourceType
, _resourceId
);
1772 OUString
SimpleResMgr::ReadString( sal_uInt32 nId
)
1774 osl::MutexGuard
aGuard(m_aAccessSafety
);
1776 DBG_ASSERT( m_pResImpl
, "SimpleResMgr::ReadString : have no impl class !" );
1777 // perhaps constructed with an invalid filename ?
1783 void* pResHandle
= NULL
;
1784 InternalResMgr
* pFallback
= m_pResImpl
;
1785 RSHEADER_TYPE
* pResHeader
= (RSHEADER_TYPE
*)m_pResImpl
->LoadGlobalRes( RSC_STRING
, nId
, &pResHandle
);
1788 osl::Guard
<osl::Mutex
> aGuard2( getResMgrMutex() );
1791 while( ! pResHandle
&& pFallback
)
1793 InternalResMgr
* pOldFallback
= pFallback
;
1794 pFallback
= ResMgrContainer::get().getNextFallback( pFallback
);
1795 if( pOldFallback
!= m_pResImpl
)
1796 ResMgrContainer::get().freeResMgr( pOldFallback
);
1799 // handle possible recursion
1800 if( pFallback
->aLocale
!= m_pResImpl
->aLocale
)
1802 pResHeader
= (RSHEADER_TYPE
*)pFallback
->LoadGlobalRes( RSC_STRING
, nId
, &pResHandle
);
1806 ResMgrContainer::get().freeResMgr( pFallback
);
1816 // sal_uIntPtr nLen = pResHeader->GetLocalOff() - sizeof(RSHEADER_TYPE);
1817 ResMgr::GetString( sReturn
, (const sal_uInt8
*)(pResHeader
+1) );
1819 // not necessary with te current implementation which holds the string table permanently, but to be sure ....
1820 // note: pFallback cannot be NULL here and is either the fallback or m_pResImpl
1821 InternalResMgr::FreeGlobalRes( pResHeader
, pResHandle
);
1822 if( m_pResImpl
!= pFallback
)
1824 osl::Guard
<osl::Mutex
> aGuard2( getResMgrMutex() );
1826 ResMgrContainer::get().freeResMgr( pFallback
);
1831 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */