1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: resmgr.cxx,v $
10 * $Revision: 1.52.30.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_tools.hxx"
37 #include <vos/signal.hxx>
38 #include <tools/debug.hxx>
40 #include <tools/table.hxx>
42 #include <tools/stream.hxx>
43 #include <tools/resmgr.hxx>
44 #include <tools/rc.hxx>
45 #include <tools/rcid.h>
46 #include <osl/endian.h>
47 #include <osl/process.h>
48 #include <osl/thread.h>
49 #include <osl/file.hxx>
50 #include <osl/mutex.hxx>
51 #include <rtl/ustrbuf.hxx>
52 #include <tools/urlobj.hxx>
53 #include <rtl/instance.hxx>
54 #include <rtl/bootstrap.hxx>
55 #include <i18npool/mslangid.hxx>
56 #include <tools/simplerm.hxx>
58 #include <tools/isofallback.hxx>
67 #define SEARCH_PATH_DELIMITER_CHAR_STRING ":"
68 #define SEARCH_PATH_DELIMITER ':'
70 #define SEARCH_PATH_DELIMITER_CHAR_STRING ";"
71 #define SEARCH_PATH_DELIMITER ';'
74 #define SEARCH_PATH_DELIMITER_STRING ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SEARCH_PATH_DELIMITER_CHAR_STRING ) )
80 static osl::Mutex
* pResMgrMutex
= NULL
;
81 static osl::Mutex
& getResMgrMutex()
85 osl::Guard
<osl::Mutex
> aGuard( *osl::Mutex::getGlobalMutex() );
87 pResMgrMutex
= new osl::Mutex();
96 friend class SimpleResMgr
;
97 friend class ResMgrContainer
;
99 ImpContent
* pContent
;
100 UINT32 nOffCorrection
;
109 com::sun::star::lang::Locale aLocale
;
110 std::hash_map
<sal_uInt64
, int>* pResUseDump
;
112 InternalResMgr( const OUString
& rFileURL
,
113 const OUString
& aPrefix
,
114 const OUString
& aResName
,
115 const com::sun::star::lang::Locale
& rLocale
);
119 BOOL
IsGlobalAvailable( RESOURCE_TYPE nRT
, sal_uInt32 nId
) const;
120 void * LoadGlobalRes( RESOURCE_TYPE nRT
, sal_uInt32 nId
,
123 void FreeGlobalRes( void *, void * );
125 SvStream
* GetBitmapStream( sal_uInt32 nResId
);
128 // =======================================================================
130 class ResMgrContainer
132 static ResMgrContainer
* pOneInstance
;
134 struct ContainerElement
136 InternalResMgr
* pResMgr
;
148 std::hash_map
< OUString
, ContainerElement
, OUStringHash
> m_aResFiles
;
149 com::sun::star::lang::Locale m_aDefLocale
;
151 ResMgrContainer() { init(); }
157 static ResMgrContainer
& get();
158 static void release();
160 InternalResMgr
* getResMgr( const OUString
& rPrefix
,
161 com::sun::star::lang::Locale
& rLocale
,
162 bool bForceNewInstance
= false
164 InternalResMgr
* getNextFallback( InternalResMgr
* pResMgr
);
166 void freeResMgr( InternalResMgr
* pResMgr
);
168 void setDefLocale( const com::sun::star::lang::Locale
& rLocale
)
169 { m_aDefLocale
= rLocale
; }
170 const com::sun::star::lang::Locale
& getDefLocale() const
171 { return m_aDefLocale
; }
174 ResMgrContainer
* ResMgrContainer::pOneInstance
= NULL
;
176 ResMgrContainer
& ResMgrContainer::get()
179 pOneInstance
= new ResMgrContainer();
180 return *pOneInstance
;
183 ResMgrContainer::~ResMgrContainer()
185 for( std::hash_map
< OUString
, ContainerElement
, OUStringHash
>::iterator it
=
186 m_aResFiles
.begin(); it
!= m_aResFiles
.end(); ++it
)
188 OSL_TRACE( "Resource file %s loaded %d times\n",
189 OUStringToOString( it
->second
.aFileURL
, osl_getThreadTextEncoding() ).getStr(),
190 it
->second
.nLoadCount
);
191 delete it
->second
.pResMgr
;
195 void ResMgrContainer::release()
201 void ResMgrContainer::init()
204 std::list
< OUString
> aDirs
;
205 sal_Int32 nIndex
= 0;
207 // 1. fixed locations
209 RTL_CONSTASCII_USTRINGPARAM("$BRAND_BASE_DIR/program/resource"));
210 rtl::Bootstrap::expandMacros(uri
);
211 aDirs
.push_back(uri
);
213 RTL_CONSTASCII_USTRINGPARAM("$OOO_BASE_DIR/program/resource"));
214 rtl::Bootstrap::expandMacros(uri
);
215 aDirs
.push_back(uri
);
217 // 2. in STAR_RESOURCEPATH
218 const sal_Char
* pEnv
= getenv( "STAR_RESOURCEPATH" );
221 OUString
aEnvPath( OStringToOUString( OString( pEnv
), osl_getThreadTextEncoding() ) );
225 OUString
aPathElement( aEnvPath
.getToken( 0, SEARCH_PATH_DELIMITER
, nIndex
) );
226 if( aPathElement
.getLength() )
229 File::getFileURLFromSystemPath( aPathElement
, aFileURL
);
230 aDirs
.push_back( aFileURL
);
235 // collect all possible resource files
236 for( std::list
< OUString
>::const_iterator dir_it
= aDirs
.begin(); dir_it
!= aDirs
.end(); ++dir_it
)
238 Directory
aDir( *dir_it
);
239 if( aDir
.open() == FileBase::E_None
)
242 while( aDir
.getNextItem( aItem
) == FileBase::E_None
)
244 FileStatus
aStatus(FileStatusMask_FileName
);
245 if( aItem
.getFileStatus( aStatus
) == FileBase::E_None
)
247 OUString aFileName
= aStatus
.getFileName();
248 if( aFileName
.getLength() < 5 )
250 if( ! aFileName
.endsWithIgnoreAsciiCaseAsciiL( ".res", 4 ) )
252 OUString aResName
= aFileName
.copy( 0, aFileName
.getLength()-4 );
253 if( m_aResFiles
.find( aResName
) != m_aResFiles
.end() )
255 OUStringBuffer
aURL( dir_it
->getLength() + aFileName
.getLength() + 1 );
256 aURL
.append( *dir_it
);
257 if( !dir_it
->endsWithIgnoreAsciiCaseAsciiL( "/", 1 ) )
258 aURL
.append( sal_Unicode('/') );
259 aURL
.append( aFileName
);
260 m_aResFiles
[ aResName
].aFileURL
= aURL
.makeStringAndClear();
264 #if OSL_DEBUG_LEVEL > 1
266 OSL_TRACE( "opening dir %s failed\n", OUStringToOString( *dir_it
, osl_getThreadTextEncoding() ).getStr() );
269 #if OSL_DEBUG_LEVEL > 1
270 for( std::hash_map
< OUString
, ContainerElement
, OUStringHash
>::const_iterator it
=
271 m_aResFiles
.begin(); it
!= m_aResFiles
.end(); ++it
)
273 OSL_TRACE( "ResMgrContainer: %s -> %s\n",
274 OUStringToOString( it
->first
, osl_getThreadTextEncoding() ).getStr(),
275 OUStringToOString( it
->second
.aFileURL
, osl_getThreadTextEncoding() ).getStr() );
279 // set default language
280 LanguageType nLang
= MsLangId::getSystemUILanguage();
281 MsLangId::convertLanguageToLocale(nLang
, m_aDefLocale
);
284 InternalResMgr
* ResMgrContainer::getResMgr( const OUString
& rPrefix
,
285 com::sun::star::lang::Locale
& rLocale
,
286 bool bForceNewInstance
289 com::sun::star::lang::Locale
aLocale( rLocale
);
290 OUStringBuffer
aSearch( rPrefix
.getLength() + 16 );
291 std::hash_map
< OUString
, ContainerElement
, OUStringHash
>::iterator it
= m_aResFiles
.end();
294 if( aLocale
.Language
.getLength() > 0 )
296 if( aLocale
.Country
.getLength() > 0 )
298 if( aLocale
.Variant
.getLength() > 0 )
302 aSearch
.append( rPrefix
);
305 aSearch
.append( aLocale
.Language
);
309 aSearch
.append( sal_Unicode('-') );
310 aSearch
.append( aLocale
.Country
);
314 aSearch
.append( sal_Unicode('-') );
315 aSearch
.append( aLocale
.Variant
);
317 it
= m_aResFiles
.find( aSearch
.makeStringAndClear() );
318 if( it
!= m_aResFiles
.end() )
320 // ensure InternalResMgr existance
321 if( ! it
->second
.pResMgr
)
323 InternalResMgr
* pImp
=
324 new InternalResMgr( it
->second
.aFileURL
, rPrefix
, it
->first
, aLocale
);
325 if( ! pImp
->Create() )
330 it
->second
.pResMgr
= pImp
;
334 if( nTries
== 0 && !aLocale
.Language
.equalsIgnoreAsciiCaseAscii( "en" ) )
336 // locale fallback failed
337 // fallback to en-US locale
339 aLocale
.Language
= OUString( RTL_CONSTASCII_USTRINGPARAM( "en" ) );
340 aLocale
.Country
= OUString( RTL_CONSTASCII_USTRINGPARAM( "US" ) );
341 aLocale
.Variant
= OUString();
344 // try if there is anything with this prefix at all
345 if( it
== m_aResFiles
.end() )
347 aLocale
= com::sun::star::lang::Locale();
348 it
= m_aResFiles
.find( rPrefix
);
349 if( it
== m_aResFiles
.end() )
351 for( it
= m_aResFiles
.begin(); it
!= m_aResFiles
.end(); ++it
)
353 if( it
->first
.matchIgnoreAsciiCase( rPrefix
) )
355 // ensure InternalResMgr existance
356 if( ! it
->second
.pResMgr
)
358 InternalResMgr
* pImp
=
359 new InternalResMgr( it
->second
.aFileURL
,
363 if( ! pImp
->Create() )
368 it
->second
.pResMgr
= pImp
;
370 // try to guess locale
371 sal_Int32 nIndex
= rPrefix
.getLength();
372 aLocale
.Language
= it
->first
.getToken( 0, '-', nIndex
);
374 aLocale
.Country
= it
->first
.getToken( 0, '-', nIndex
);
376 aLocale
.Variant
= it
->first
.getToken( 0, '-', nIndex
);
383 if( it
== m_aResFiles
.end() )
385 OUStringBuffer sKey
= rPrefix
;
386 sKey
.append( rLocale
.Language
);
387 if( rLocale
.Country
.getLength() )
389 sKey
.append( sal_Unicode('-') );
390 sKey
.append( rLocale
.Country
);
392 if( rLocale
.Variant
.getLength() )
394 sKey
.append( sal_Unicode('-') );
395 sKey
.append( rLocale
.Variant
);
396 } // if( aLocale.Variant.getLength() )
397 ::rtl::OUString sURL
= sKey
.makeStringAndClear();
398 sURL
+= ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".res"));
399 if ( m_aResFiles
.find(sURL
) == m_aResFiles
.end() )
401 m_aResFiles
[ sURL
].aFileURL
= sURL
;
402 return getResMgr(rPrefix
,rLocale
,bForceNewInstance
);
403 } // if ( m_aResFiles.find(sURL) == m_aResFiles.end() )
408 // at this point it->second.pResMgr must be filled either by creating a new one
409 // (then the refcount is still 0) or because we already had one
410 InternalResMgr
* pImp
= it
->second
.pResMgr
;
412 if( it
->second
.nRefCount
== 0 )
413 it
->second
.nLoadCount
++;
416 if( bForceNewInstance
)
418 if( it
->second
.nRefCount
== 0 )
420 // shortcut: the match algorithm already created the InternalResMgr
421 // take it instead of creating yet another one
422 it
->second
.pResMgr
= NULL
;
423 pImp
->bSingular
= true;
427 pImp
= new InternalResMgr( it
->second
.aFileURL
, rPrefix
, it
->first
, aLocale
);
428 pImp
->bSingular
= true;
429 if( !pImp
->Create() )
435 it
->second
.nLoadCount
++;
439 it
->second
.nRefCount
++;
444 InternalResMgr
* ResMgrContainer::getNextFallback( InternalResMgr
* pMgr
)
446 com::sun::star::lang::Locale aLocale
= pMgr
->aLocale
;
447 if( aLocale
.Variant
.getLength() )
448 aLocale
.Variant
= OUString();
449 else if( aLocale
.Country
.getLength() )
450 aLocale
.Country
= OUString();
451 else if( ! aLocale
.Language
.equalsIgnoreAsciiCaseAscii( "en" ) )
453 aLocale
.Language
= OUString( RTL_CONSTASCII_USTRINGPARAM( "en" ) );
454 aLocale
.Country
= OUString( RTL_CONSTASCII_USTRINGPARAM( "US" ) );
456 InternalResMgr
* pNext
= getResMgr( pMgr
->aPrefix
, aLocale
, pMgr
->bSingular
);
458 if( pNext
== pMgr
|| pNext
->aResName
.equals( pMgr
->aResName
) )
460 if( pNext
->bSingular
)
467 void ResMgrContainer::freeResMgr( InternalResMgr
* pResMgr
)
469 if( pResMgr
->bSingular
)
473 std::hash_map
< OUString
, ContainerElement
, OUStringHash
>::iterator it
=
474 m_aResFiles
.find( pResMgr
->aResName
);
475 if( it
!= m_aResFiles
.end() )
477 DBG_ASSERT( it
->second
.nRefCount
> 0, "InternalResMgr freed too often" );
478 if( it
->second
.nRefCount
> 0 )
479 it
->second
.nRefCount
--;
480 if( it
->second
.nRefCount
== 0 )
482 delete it
->second
.pResMgr
;
483 it
->second
.pResMgr
= NULL
;
489 // =======================================================================
491 void Resource::TestRes()
494 m_pResMgr
->TestStack( this );
499 sal_uInt64 nTypeAndId
;
503 struct ImpContentLessCompare
: public ::std::binary_function
< ImpContent
, ImpContent
, bool>
505 inline bool operator() (const ImpContent
& lhs
, const ImpContent
& rhs
) const
507 return lhs
.nTypeAndId
< rhs
.nTypeAndId
;
511 struct ImpContentMixLessCompare
: public ::std::binary_function
< ImpContent
, sal_uInt64
, bool>
513 inline bool operator() (const ImpContent
& lhs
, const sal_uInt64
& rhs
) const
515 return lhs
.nTypeAndId
< rhs
;
517 inline bool operator() (const sal_uInt64
& lhs
, const ImpContent
& rhs
) const
519 return lhs
< rhs
.nTypeAndId
;
524 // =======================================================================
526 static ResHookProc pImplResHookProc
= 0;
528 // =======================================================================
530 SvStream
* InternalResMgr::GetBitmapStream( sal_uInt32 nId
)
532 // Anfang der Strings suchen
533 ImpContent
* pFind
= ::std::lower_bound(pContent
,
535 ((sal_uInt64(RT_SYS_BITMAP
) << 32) | nId
),
536 ImpContentMixLessCompare());
537 if ( (pFind
!= (pContent
+ nEntries
)) && (pFind
->nTypeAndId
== ((sal_uInt64(RT_SYS_BITMAP
) << 32) | nId
)) )
539 pStm
->Seek( pFind
->nOffset
);
545 // -----------------------------------------------------------------------
547 InternalResMgr::InternalResMgr( const OUString
& rFileURL
,
548 const OUString
& rPrefix
,
549 const OUString
& rResName
,
550 const com::sun::star::lang::Locale
& rLocale
)
552 , pStringBlock( NULL
)
554 , bEqual2Content( TRUE
)
556 , aFileName( rFileURL
)
558 , aResName( rResName
)
565 // -----------------------------------------------------------------------
567 InternalResMgr::~InternalResMgr()
569 rtl_freeMemory(pContent
);
570 rtl_freeMemory(pStringBlock
);
576 const sal_Char
* pLogFile
= getenv( "STAR_RESOURCE_LOGGING" );
579 SvFileStream
aStm( UniString( pLogFile
, RTL_TEXTENCODING_ASCII_US
), STREAM_WRITE
);
580 aStm
.Seek( STREAM_SEEK_TO_END
);
581 ByteString
aLine( "FileName: " );
582 aLine
.Append( ByteString( OUStringToOString( aFileName
, RTL_TEXTENCODING_UTF8
) ) );
583 aStm
.WriteLine( aLine
);
585 for( std::hash_map
<sal_uInt64
, int>::const_iterator it
= pResUseDump
->begin();
586 it
!= pResUseDump
->end(); ++it
)
588 sal_uInt64 nKeyId
= it
->first
;
589 aLine
.Assign( "Type/Id: " );
590 aLine
.Append( ByteString::CreateFromInt32( sal::static_int_cast
< sal_Int32
>((nKeyId
>> 32) & 0xFFFFFFFF) ) );
592 aLine
.Append( ByteString::CreateFromInt32( sal::static_int_cast
< sal_Int32
>(nKeyId
& 0xFFFFFFFF) ) );
593 aStm
.WriteLine( aLine
);
602 // -----------------------------------------------------------------------
605 BOOL
InternalResMgr::Create()
607 ResMgrContainer::get();
610 pStm
= new SvFileStream( aFileName
, (STREAM_READ
| STREAM_SHARE_DENYWRITE
| STREAM_NOCREATE
) );
611 if( pStm
->GetError() == 0 )
615 pStm
->Seek( STREAM_SEEK_TO_END
);
617 if( ( pInternalResMgr->pHead = (RSHEADER_TYPE *)mmap( 0, nResourceFileSize,
618 PROT_READ, MAP_PRIVATE,
619 fRes, 0 ) ) != (RSHEADER_TYPE *)-1)
621 pStm
->SeekRel( - (int)sizeof( lContLen
) );
622 pStm
->Read( &lContLen
, sizeof( lContLen
) );
623 // is bigendian, swab to the right endian
624 lContLen
= ResMgr::GetLong( &lContLen
);
625 pStm
->SeekRel( -lContLen
);
626 // allocate stored ImpContent data (12 bytes per unit)
627 BYTE
* pContentBuf
= (BYTE
*)rtl_allocateMemory( lContLen
);
628 pStm
->Read( pContentBuf
, lContLen
);
629 // allocate ImpContent space (sizeof(ImpContent) per unit, not necessarily 12)
630 pContent
= (ImpContent
*)rtl_allocateMemory( sizeof(ImpContent
)*lContLen
/12 );
631 // Auf die Anzahl der ImpContent k�rzen
632 nEntries
= (UINT32
)lContLen
/ 12;
633 bEqual2Content
= TRUE
; // Die Daten der Resourcen liegen
634 // genauso wie das Inhaltsverzeichnis
639 const sal_Char
* pLogFile
= getenv( "STAR_RESOURCE_LOGGING" );
642 pResUseDump
= new std::hash_map
<sal_uInt64
, int>;
643 for( sal_uInt32 i
= 0; i
< nEntries
; ++i
)
644 (*pResUseDump
)[pContent
[i
].nTypeAndId
] = 1;
647 // swap the content to the right endian
648 pContent
[0].nTypeAndId
= ResMgr::GetUInt64( pContentBuf
);
649 pContent
[0].nOffset
= ResMgr::GetLong( pContentBuf
+8 );
650 sal_uInt32 nCount
= nEntries
- 1;
651 for( sal_uInt32 i
= 0,j
=1; i
< nCount
; ++i
,++j
)
653 // swap the content to the right endian
654 pContent
[j
].nTypeAndId
= ResMgr::GetUInt64( pContentBuf
+ (12*j
) );
655 pContent
[j
].nOffset
= ResMgr::GetLong( pContentBuf
+ (12*j
+8) );
656 if( pContent
[i
].nTypeAndId
>= pContent
[j
].nTypeAndId
)
658 if( (pContent
[i
].nTypeAndId
& 0xFFFFFFFF00000000LL
) == (pContent
[j
].nTypeAndId
& 0xFFFFFFFF00000000LL
)
659 && pContent
[i
].nOffset
>= pContent
[j
].nOffset
)
660 bEqual2Content
= FALSE
;
663 rtl_freeMemory( pContentBuf
);
665 OSL_ENSURE( bSorted
, "content not sorted" );
667 OSL_ENSURE( bEqual2Content
, "resource structure wrong" );
669 ::std::sort(pContent
,pContent
+nEntries
,ImpContentLessCompare());
670 // qsort( pContent, nEntries, sizeof( ImpContent ), Compare );
678 // -----------------------------------------------------------------------
680 BOOL
InternalResMgr::IsGlobalAvailable( RESOURCE_TYPE nRT
, sal_uInt32 nId
) const
682 // Anfang der Strings suchen
683 sal_uInt64 nValue
= ((sal_uInt64(nRT
) << 32) | nId
);
684 ImpContent
* pFind
= ::std::lower_bound(pContent
,
687 ImpContentMixLessCompare());
688 return (pFind
!= (pContent
+ nEntries
)) && (pFind
->nTypeAndId
== nValue
);
691 // -----------------------------------------------------------------------
693 void* InternalResMgr::LoadGlobalRes( RESOURCE_TYPE nRT
, sal_uInt32 nId
,
698 pResUseDump
->erase( (sal_uInt64(nRT
) << 32) | nId
);
700 // Anfang der Strings suchen
701 sal_uInt64 nValue
= ((sal_uInt64(nRT
) << 32) | nId
);
702 ImpContent
* pEnd
= (pContent
+ nEntries
);
703 ImpContent
* pFind
= ::std::lower_bound( pContent
,
706 ImpContentMixLessCompare());
707 if( pFind
&& (pFind
!= pEnd
) && (pFind
->nTypeAndId
== nValue
) )
709 if( nRT
== RSC_STRING
&& bEqual2Content
)
711 // String Optimierung
714 // Anfang der Strings suchen
715 ImpContent
* pFirst
= pFind
;
716 ImpContent
* pLast
= pFirst
;
717 while( pFirst
> pContent
&& ((pFirst
-1)->nTypeAndId
>> 32) == RSC_STRING
)
719 while( pLast
< pEnd
&& (pLast
->nTypeAndId
>> 32) == RSC_STRING
)
721 nOffCorrection
= pFirst
->nOffset
;
724 pStm
->Seek( pLast
->nOffset
);
726 pStm
->Read( &aHdr
, sizeof( aHdr
) );
727 nSize
= pLast
->nOffset
+ aHdr
.GetGlobOff() - nOffCorrection
;
728 pStringBlock
= (BYTE
*)rtl_allocateMemory( nSize
);
729 pStm
->Seek( pFirst
->nOffset
);
730 pStm
->Read( pStringBlock
, nSize
);
732 *pResHandle
= pStringBlock
;
733 return (BYTE
*)pStringBlock
+ pFind
->nOffset
- nOffCorrection
;
734 } // if( nRT == RSC_STRING && bEqual2Content )
738 RSHEADER_TYPE aHeader
;
739 pStm
->Seek( pFind
->nOffset
);
740 pStm
->Read( &aHeader
, sizeof( RSHEADER_TYPE
) );
741 void * pRes
= rtl_allocateMemory( aHeader
.GetGlobOff() );
742 memcpy( pRes
, &aHeader
, sizeof( RSHEADER_TYPE
) );
743 pStm
->Read( (BYTE
*)pRes
+ sizeof( RSHEADER_TYPE
),
744 aHeader
.GetGlobOff() - sizeof( RSHEADER_TYPE
) );
747 } // if( pFind && (pFind != pEnd) && (pFind->nTypeAndId == nValue) )
753 // -----------------------------------------------------------------------
755 void InternalResMgr::FreeGlobalRes( void * pResHandle
, void * pResource
)
758 // REsource wurde extra allokiert
759 rtl_freeMemory(pResource
);
762 // =======================================================================
766 UniString
GetTypeRes_Impl( const ResId
& rTypeId
)
768 // Funktion verlassen, falls Resourcefehler in dieser Funktion
769 static int bInUse
= FALSE
;
770 UniString
aTypStr( UniString::CreateFromInt32( rTypeId
.GetId() ) );
776 ResId
aResId( sal_uInt32(RSCVERSION_ID
), *rTypeId
.GetResMgr() );
777 aResId
.SetRT( RSC_VERSIONCONTROL
);
779 if ( rTypeId
.GetResMgr()->GetResource( aResId
) )
781 rTypeId
.SetRT( RSC_STRING
);
782 if ( rTypeId
.GetResMgr()->IsAvailable( rTypeId
) )
784 aTypStr
= UniString( rTypeId
);
785 // Versions Resource Klassenzeiger ans Ende setzen
786 rTypeId
.GetResMgr()->Increment( sizeof( RSHEADER_TYPE
) );
795 // -----------------------------------------------------------------------
797 void ResMgr::RscError_Impl( const sal_Char
* pMessage
, ResMgr
* pResMgr
,
798 RESOURCE_TYPE nRT
, sal_uInt32 nId
,
799 std::vector
< ImpRCStack
>& rResStack
, int nDepth
)
801 // create a separate ResMgr with its own stack
802 // first get a second reference of the InternalResMgr
803 InternalResMgr
* pImp
=
804 ResMgrContainer::get().getResMgr( pResMgr
->pImpRes
->aPrefix
,
805 pResMgr
->pImpRes
->aLocale
,
808 ResMgr
* pNewResMgr
= new ResMgr( pImp
);
810 ByteString aStr
= OUStringToOString( pResMgr
->GetFileName(), RTL_TEXTENCODING_UTF8
);
814 aStr
.Append( "Class: " );
815 aStr
.Append( ByteString( GetTypeRes_Impl( ResId( nRT
, *pNewResMgr
) ), RTL_TEXTENCODING_UTF8
) );
816 aStr
.Append( ", Id: " );
817 aStr
.Append( ByteString::CreateFromInt32( (long)nId
) );
819 aStr
.Append( pMessage
);
821 aStr
.Append( "\nResource Stack\n" );
824 aStr
.Append( "Class: " );
825 aStr
.Append( ByteString( GetTypeRes_Impl( ResId( rResStack
[nDepth
].pResource
->GetRT(), *pNewResMgr
) ), RTL_TEXTENCODING_UTF8
) );
826 aStr
.Append( ", Id: " );
827 aStr
.Append( ByteString::CreateFromInt32( (long)rResStack
[nDepth
].pResource
->GetId() ) );
834 DBG_ERROR( aStr
.GetBuffer() );
839 // =======================================================================
841 static void RscException_Impl()
843 switch ( NAMESPACE_VOS(OSignalHandler
)::raise( OSL_SIGNAL_USER_RESOURCEFAILURE
, (void*)"" ) )
845 case NAMESPACE_VOS(OSignalHandler
)::TAction_CallNextHandler
:
848 case NAMESPACE_VOS(OSignalHandler
)::TAction_Ignore
:
851 case NAMESPACE_VOS(OSignalHandler
)::TAction_AbortApplication
:
854 case NAMESPACE_VOS(OSignalHandler
)::TAction_KillApplication
:
859 // =======================================================================
861 void ImpRCStack::Init( ResMgr
* pMgr
, const Resource
* pObj
, sal_uInt32 Id
)
868 nId
= Id
& ~RSC_DONTRELEASE
; //TLX: Besser Init aendern
870 if ( !(Id
& RSC_DONTRELEASE
) )
871 Flags
|= RC_AUTORELEASE
;
874 // -----------------------------------------------------------------------
876 void ImpRCStack::Clear()
887 // -----------------------------------------------------------------------
889 static RSHEADER_TYPE
* LocalResource( const ImpRCStack
* pStack
,
890 RESOURCE_TYPE nRTType
,
893 // Gibt die Position der Resource zurueck, wenn sie gefunden wurde.
894 // Ansonsten gibt die Funktion Null zurueck.
895 RSHEADER_TYPE
* pTmp
; // Zeiger auf Kind-Resourceobjekte
896 RSHEADER_TYPE
* pEnd
; // Zeiger auf das Ende der Resource
898 if ( pStack
->pResource
&& pStack
->pClassRes
)
900 pTmp
= (RSHEADER_TYPE
*)
901 ((BYTE
*)pStack
->pResource
+ pStack
->pResource
->GetLocalOff());
902 pEnd
= (RSHEADER_TYPE
*)
903 ((BYTE
*)pStack
->pResource
+ pStack
->pResource
->GetGlobOff());
904 while ( pTmp
!= pEnd
)
906 if ( pTmp
->GetRT() == nRTType
&& pTmp
->GetId() == nId
)
908 pTmp
= (RSHEADER_TYPE
*)((BYTE
*)pTmp
+ pTmp
->GetGlobOff());
915 // =======================================================================
917 void* ResMgr::pEmptyBuffer
= NULL
;
919 void* ResMgr::getEmptyBuffer()
922 pEmptyBuffer
= rtl_allocateZeroMemory( 1024 );
926 void ResMgr::DestroyAllResMgr()
929 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
932 rtl_freeMemory( pEmptyBuffer
);
935 ResMgrContainer::release();
941 // -----------------------------------------------------------------------
943 void ResMgr::Init( const OUString
& rFileName
)
945 (void) rFileName
; // avoid warning about unused parameter
946 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
951 ByteString
aStr( "Resourcefile not found:\n" );
952 aStr
+= ByteString( OUStringToOString( rFileName
, RTL_TEXTENCODING_UTF8
) );
953 DBG_ERROR( aStr
.GetBuffer() );
960 void* aResHandle
= 0; // Hilfvariable fuer Resource
961 void* pVoid
; // Zeiger auf die Resource
963 pVoid
= pImpRes
->LoadGlobalRes( RSC_VERSIONCONTROL
, RSCVERSION_ID
,
966 pImpRes
->FreeGlobalRes( aResHandle
, pVoid
);
969 ByteString
aStr( "Wrong version:\n" );
970 aStr
+= ByteString( OUStringToOString( pImpRes
->aFileName
, RTL_TEXTENCODING_UTF8
) );
971 DbgError( aStr
.GetBuffer() );
977 pFallbackResMgr
= pOriginalResMgr
= NULL
;
981 // -----------------------------------------------------------------------
983 ResMgr::ResMgr( InternalResMgr
* pImpMgr
)
986 Init( pImpMgr
->aFileName
);
989 // -----------------------------------------------------------------------
993 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
995 ResMgrContainer::get().freeResMgr( pImpRes
);
997 // clean up possible left rc stack frames
998 while( nCurStack
> 0 )
1000 if( ( aStack
[nCurStack
].Flags
& (RC_GLOBAL
| RC_NOTFOUND
) ) == RC_GLOBAL
)
1001 pImpRes
->FreeGlobalRes( aStack
[nCurStack
].aResHandle
,
1002 aStack
[nCurStack
].pResource
);
1008 void ResMgr::incStack()
1011 if( nCurStack
>= int(aStack
.size()) )
1012 aStack
.push_back( ImpRCStack() );
1013 aStack
[nCurStack
].Clear();
1015 DBG_ASSERT( nCurStack
< 32, "Resource stack unreasonably large" );
1018 void ResMgr::decStack()
1020 DBG_ASSERT( nCurStack
> 0, "resource stack underrun !" );
1021 if( (aStack
[nCurStack
].Flags
& RC_FALLBACK_UP
) )
1024 // warning: this will delete *this, see below
1025 pOriginalResMgr
->decStack();
1029 ImpRCStack
& rTop
= aStack
[nCurStack
];
1030 if( (rTop
.Flags
& RC_FALLBACK_DOWN
) )
1032 #if OSL_DEBUG_LEVEL > 1
1033 OSL_TRACE( "returning from fallback %s\n",
1034 OUStringToOString(pFallbackResMgr
->GetFileName(), osl_getThreadTextEncoding() ).getStr() );
1036 delete pFallbackResMgr
;
1037 pFallbackResMgr
= NULL
;
1045 void ResMgr::TestStack( const Resource
* pResObj
)
1047 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1049 if ( DbgIsResource() )
1051 for( int i
= 1; i
<= nCurStack
; ++i
)
1053 if ( aStack
[i
].pResObj
== pResObj
)
1056 RscError_Impl( "Resource not freed! ", this,
1057 aStack
[i
].pResource
->GetRT(),
1058 aStack
[i
].pResource
->GetId(),
1068 void ResMgr::TestStack( const Resource
* )
1074 // -----------------------------------------------------------------------
1075 BOOL
ResMgr::IsAvailable( const ResId
& rId
, const Resource
* pResObj
) const
1077 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1079 BOOL bAvailable
= FALSE
;
1080 RSHEADER_TYPE
* pClassRes
= rId
.GetpResource();
1081 RESOURCE_TYPE nRT
= rId
.GetRT2();
1082 sal_uInt32 nId
= rId
.GetId();
1083 const ResMgr
* pMgr
= rId
.GetResMgr();
1088 if( pMgr
->pFallbackResMgr
)
1091 aId
.SetResMgr( NULL
);
1092 return pMgr
->pFallbackResMgr
->IsAvailable( aId
, pResObj
);
1095 if ( !pResObj
|| pResObj
== pMgr
->aStack
[pMgr
->nCurStack
].pResObj
)
1098 pClassRes
= LocalResource( &pMgr
->aStack
[pMgr
->nCurStack
], nRT
, nId
);
1101 if ( pClassRes
->GetRT() == nRT
)
1106 // vieleicht globale Resource
1108 bAvailable
= pMgr
->pImpRes
->IsGlobalAvailable( nRT
, nId
);
1113 // -----------------------------------------------------------------------
1115 void* ResMgr::GetClass()
1117 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1119 if( pFallbackResMgr
)
1120 return pFallbackResMgr
->GetClass();
1122 return aStack
[nCurStack
].pClassRes
;
1125 // -----------------------------------------------------------------------
1127 BOOL
ResMgr::GetResource( const ResId
& rId
, const Resource
* pResObj
)
1129 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1131 if( pFallbackResMgr
)
1134 aId
.SetResMgr( NULL
);
1135 return pFallbackResMgr
->GetResource( aId
, pResObj
);
1138 ResMgr
* pMgr
= rId
.GetResMgr();
1139 if ( pMgr
&& (this != pMgr
) )
1140 return pMgr
->GetResource( rId
, pResObj
);
1142 // normally Increment will pop the context; this is
1143 // not possible in RC_NOTFOUND case, so pop a frame here
1144 ImpRCStack
* pTop
= &aStack
[nCurStack
];
1145 if( (pTop
->Flags
& RC_NOTFOUND
) )
1150 RSHEADER_TYPE
* pClassRes
= rId
.GetpResource();
1151 RESOURCE_TYPE nRT
= rId
.GetRT2();
1152 sal_uInt32 nId
= rId
.GetId();
1155 pTop
= &aStack
[nCurStack
];
1156 pTop
->Init( pMgr
, pResObj
, nId
|
1157 (rId
.IsAutoRelease() ? 0 : RSC_DONTRELEASE
) );
1161 if ( pClassRes
->GetRT() == nRT
)
1162 pTop
->pClassRes
= pClassRes
;
1166 RscError_Impl( "Different class and resource type!",
1167 this, nRT
, nId
, aStack
, nCurStack
-1 );
1169 pTop
->Flags
|= RC_NOTFOUND
;
1170 pTop
->pClassRes
= getEmptyBuffer();
1171 pTop
->pResource
= (RSHEADER_TYPE
*)pTop
->pClassRes
;
1177 OSL_ENSURE( nCurStack
> 0, "stack of 1 to shallow" );
1178 pTop
->pClassRes
= LocalResource( &aStack
[nCurStack
-1], nRT
, nId
);
1181 if ( pTop
->pClassRes
)
1182 // lokale Resource, nicht system Resource
1183 pTop
->pResource
= (RSHEADER_TYPE
*)pTop
->pClassRes
;
1186 pTop
->pClassRes
= pImpRes
->LoadGlobalRes( nRT
, nId
, &pTop
->aResHandle
);
1187 if ( pTop
->pClassRes
)
1189 pTop
->Flags
|= RC_GLOBAL
;
1190 pTop
->pResource
= (RSHEADER_TYPE
*)pTop
->pClassRes
;
1194 // try to get a fallback resource
1195 pFallbackResMgr
= CreateFallbackResMgr( rId
, pResObj
);
1196 if( pFallbackResMgr
)
1198 pTop
->Flags
|= RC_FALLBACK_DOWN
;
1200 ByteString
aMess( "found resource " );
1201 aMess
.Append( ByteString::CreateFromInt32( nId
) );
1202 aMess
.Append( " in fallback " );
1203 aMess
.Append( ByteString( OUStringToOString( pFallbackResMgr
->GetFileName(), osl_getThreadTextEncoding() ) ) );
1204 aMess
.Append( "\n" );
1205 RscError_Impl( aMess
.GetBuffer(),
1206 this, nRT
, nId
, aStack
, nCurStack
-1 );
1212 RscError_Impl( "Cannot load resource! ",
1213 this, nRT
, nId
, aStack
, nCurStack
-1 );
1215 pTop
->Flags
|= RC_NOTFOUND
;
1216 pTop
->pClassRes
= getEmptyBuffer();
1217 pTop
->pResource
= (RSHEADER_TYPE
*)pTop
->pClassRes
;
1226 // -----------------------------------------------------------------------
1228 void * ResMgr::GetResourceSkipHeader( const ResId
& rResId
, ResMgr
** ppResMgr
)
1230 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1232 DBG_ASSERT( rResId
.GetResMgr(), "illegal ResId without ResMgr" );
1233 *ppResMgr
= rResId
.GetResMgr();
1236 (*ppResMgr
)->GetResource( rResId
);
1237 (*ppResMgr
)->Increment( sizeof( RSHEADER_TYPE
) );
1238 return (*ppResMgr
)->GetClass();
1240 return getEmptyBuffer();
1243 // -----------------------------------------------------------------------
1245 void ResMgr::PopContext( const Resource
* pResObj
)
1247 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1249 if( pFallbackResMgr
)
1251 pFallbackResMgr
->PopContext( pResObj
);
1256 if ( DbgIsResource() )
1258 if ( (aStack
[nCurStack
].pResObj
!= pResObj
) || nCurStack
== 0 )
1260 RscError_Impl( "Cannot free resource! ", this,
1261 RSC_NOTYPE
, 0, aStack
, nCurStack
);
1266 if ( nCurStack
> 0 )
1268 ImpRCStack
* pTop
= &aStack
[nCurStack
];
1270 if ( DbgIsResource() && !(pTop
->Flags
& RC_NOTFOUND
) )
1272 void* pRes
= (BYTE
*)pTop
->pResource
+
1273 pTop
->pResource
->GetLocalOff();
1275 if ( pTop
->pClassRes
!= pRes
)
1277 RscError_Impl( "Classpointer not at the end!",
1278 this, pTop
->pResource
->GetRT(),
1279 pTop
->pResource
->GetId(),
1280 aStack
, nCurStack
-1 );
1285 // Resource freigeben
1286 if( (pTop
->Flags
& (RC_GLOBAL
| RC_NOTFOUND
)) == RC_GLOBAL
)
1287 // kann auch Fremd-Ressource sein
1288 pImpRes
->FreeGlobalRes( pTop
->aResHandle
, pTop
->pResource
);
1293 // -----------------------------------------------------------------------
1295 RSHEADER_TYPE
* ResMgr::CreateBlock( const ResId
& rId
)
1297 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1299 if( pFallbackResMgr
)
1302 aId
.SetResMgr( NULL
);
1303 return pFallbackResMgr
->CreateBlock( aId
);
1306 RSHEADER_TYPE
* pHeader
= NULL
;
1307 if ( GetResource( rId
) )
1309 // Der Zeiger steht am Anfang, deswegen zeigt der Klassen-Pointer
1310 // auf den Header und die restliche Groesse ist die Gesammte.
1311 pHeader
= (RSHEADER_TYPE
*)rtl_allocateMemory( GetRemainSize() );
1312 memcpy( pHeader
, GetClass(), GetRemainSize() );
1313 Increment( pHeader
->GetLocalOff() ); //ans Ende setzen
1314 if ( pHeader
->GetLocalOff() != pHeader
->GetGlobOff() )
1315 // Hat Sub-Ressourcen, deshalb extra freigeben
1322 // ------------------------------------------------------------------
1324 INT16
ResMgr::GetShort( void * pShort
)
1326 return ((*((sal_uInt8
*)pShort
+ 0) << 8) |
1327 (*((sal_uInt8
*)pShort
+ 1) << 0) );
1330 // ------------------------------------------------------------------
1332 INT32
ResMgr::GetLong( void * pLong
)
1334 return ((*((sal_uInt8
*)pLong
+ 0) << 24) |
1335 (*((sal_uInt8
*)pLong
+ 1) << 16) |
1336 (*((sal_uInt8
*)pLong
+ 2) << 8) |
1337 (*((sal_uInt8
*)pLong
+ 3) << 0) );
1340 // ------------------------------------------------------------------
1342 sal_uInt64
ResMgr::GetUInt64( void* pDatum
)
1344 return ((sal_uInt64(*((sal_uInt8
*)pDatum
+ 0)) << 56) |
1345 (sal_uInt64(*((sal_uInt8
*)pDatum
+ 1)) << 48) |
1346 (sal_uInt64(*((sal_uInt8
*)pDatum
+ 2)) << 40) |
1347 (sal_uInt64(*((sal_uInt8
*)pDatum
+ 3)) << 32) |
1348 (sal_uInt64(*((sal_uInt8
*)pDatum
+ 4)) << 24) |
1349 (sal_uInt64(*((sal_uInt8
*)pDatum
+ 5)) << 16) |
1350 (sal_uInt64(*((sal_uInt8
*)pDatum
+ 6)) << 8) |
1351 (sal_uInt64(*((sal_uInt8
*)pDatum
+ 7)) << 0) );
1354 // -----------------------------------------------------------------------
1355 sal_uInt32
ResMgr::GetStringWithoutHook( UniString
& rStr
, const BYTE
* pStr
)
1357 sal_uInt32 nRet
= GetStringSize( pStr
);
1358 UniString
aString( (sal_Char
*)pStr
, RTL_TEXTENCODING_UTF8
,
1359 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_MAPTOPRIVATE
|
1360 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT
|
1361 RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT
);
1366 sal_uInt32
ResMgr::GetString( UniString
& rStr
, const BYTE
* pStr
)
1369 sal_uInt32 nRet
= GetStringWithoutHook( aString
, pStr
);
1370 if ( pImplResHookProc
)
1371 pImplResHookProc( aString
);
1376 // ------------------------------------------------------------------
1378 sal_uInt32
ResMgr::GetStringSize( const BYTE
* pStr
)
1380 return GetStringSize( strlen( (const char*)pStr
) );
1383 // -----------------------------------------------------------------------
1385 sal_uInt32
ResMgr::GetRemainSize()
1387 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1389 if( pFallbackResMgr
)
1390 return pFallbackResMgr
->GetRemainSize();
1392 const ImpRCStack
& rTop
= aStack
[nCurStack
];
1393 return (sal_uInt32
)((long)(BYTE
*)rTop
.pResource
+
1394 rTop
.pResource
->GetLocalOff() -
1395 (long)(BYTE
*)rTop
.pClassRes
);
1398 // -----------------------------------------------------------------------
1400 void* ResMgr::Increment( sal_uInt32 nSize
)
1402 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1404 if( pFallbackResMgr
)
1405 return pFallbackResMgr
->Increment( nSize
);
1407 ImpRCStack
& rStack
= aStack
[nCurStack
];
1408 if( (rStack
.Flags
& RC_NOTFOUND
) )
1409 return rStack
.pClassRes
;
1411 BYTE
* pClassRes
= (BYTE
*)rStack
.pClassRes
+ nSize
;
1413 rStack
.pClassRes
= pClassRes
;
1415 RSHEADER_TYPE
* pRes
= rStack
.pResource
;
1417 sal_uInt32 nLocalOff
= pRes
->GetLocalOff();
1418 if ( (pRes
->GetGlobOff() == nLocalOff
) &&
1419 (((char*)pRes
+ nLocalOff
) == rStack
.pClassRes
) &&
1420 (rStack
.Flags
& RC_AUTORELEASE
))
1422 PopContext( rStack
.pResObj
);
1428 ResMgr
* ResMgr::CreateFallbackResMgr( const ResId
& rId
, const Resource
* pResource
)
1430 ResMgr
*pFallback
= NULL
;
1433 // get the next fallback level in resource file scope
1434 InternalResMgr
* pRes
= ResMgrContainer::get().getNextFallback( pImpRes
);
1437 // check that the fallback locale is not already in the chain of
1438 // fallbacks - prevent fallback loops
1439 ResMgr
* pResMgr
= this;
1441 ( pResMgr
->pImpRes
->aLocale
.Language
!= pRes
->aLocale
.Language
||
1442 pResMgr
->pImpRes
->aLocale
.Country
!= pRes
->aLocale
.Country
||
1443 pResMgr
->pImpRes
->aLocale
.Variant
!= pRes
->aLocale
.Variant
)
1446 pResMgr
= pResMgr
->pOriginalResMgr
;
1450 // found a recursion, no fallback possible
1451 ResMgrContainer::get().freeResMgr( pRes
);
1454 OSL_TRACE( "trying fallback: %s\n", OUStringToOString( pRes
->aFileName
, osl_getThreadTextEncoding() ).getStr() );
1455 pFallback
= new ResMgr( pRes
);
1456 pFallback
->pOriginalResMgr
= this;
1457 // try to recreate the resource stack
1458 bool bHaveStack
= true;
1459 for( int i
= 1; i
< nCurStack
; i
++ )
1461 if( !aStack
[i
].pResource
)
1466 ResId
aId( aStack
[i
].pResource
->GetId(), *pFallbackResMgr
);
1467 aId
.SetRT( aStack
[i
].pResource
->GetRT() );
1468 if( !pFallback
->GetResource( aId
) )
1476 ResId
aId( rId
.GetId(), *pFallback
);
1477 aId
.SetRT( rId
.GetRT() );
1478 if( !pFallback
->GetResource( aId
, pResource
) )
1481 pFallback
->aStack
[pFallback
->nCurStack
].Flags
|= RC_FALLBACK_UP
;
1493 //---------------------------------------------------------------------------
1495 // method left here for SDK compatibility,
1496 // used in "framework/source/services/substitutepathvars.cxx"
1498 // phone numbers no longer in use for resource files
1500 //---------------------------------------------------------------------------
1502 const char* ResMgr::GetLang( LanguageType
& nType
, USHORT nPrio
)
1504 if ( nType
== LANGUAGE_SYSTEM
|| nType
== LANGUAGE_DONTKNOW
)
1505 nType
= MsLangId::getSystemUILanguage();
1511 case LANGUAGE_DANISH
:
1514 case LANGUAGE_DUTCH
:
1515 case LANGUAGE_DUTCH_BELGIAN
:
1518 case LANGUAGE_ENGLISH
:
1519 case LANGUAGE_ENGLISH_UK
:
1520 case LANGUAGE_ENGLISH_EIRE
:
1521 case LANGUAGE_ENGLISH_SAFRICA
:
1522 case LANGUAGE_ENGLISH_JAMAICA
:
1523 case LANGUAGE_ENGLISH_BELIZE
:
1524 case LANGUAGE_ENGLISH_TRINIDAD
:
1525 case LANGUAGE_ENGLISH_ZIMBABWE
:
1526 case LANGUAGE_ENGLISH_PHILIPPINES
:
1529 case LANGUAGE_ENGLISH_US
:
1530 case LANGUAGE_ENGLISH_CAN
:
1533 case LANGUAGE_ENGLISH_AUS
:
1534 case LANGUAGE_ENGLISH_NZ
:
1536 case LANGUAGE_ESTONIAN
:
1540 case LANGUAGE_FINNISH
:
1543 case LANGUAGE_FRENCH_CANADIAN
:
1546 case LANGUAGE_FRENCH
:
1547 case LANGUAGE_FRENCH_BELGIAN
:
1548 case LANGUAGE_FRENCH_SWISS
:
1549 case LANGUAGE_FRENCH_LUXEMBOURG
:
1550 case LANGUAGE_FRENCH_MONACO
:
1553 case LANGUAGE_GERMAN
:
1554 case LANGUAGE_GERMAN_SWISS
:
1555 case LANGUAGE_GERMAN_AUSTRIAN
:
1556 case LANGUAGE_GERMAN_LUXEMBOURG
:
1557 case LANGUAGE_GERMAN_LIECHTENSTEIN
:
1560 case LANGUAGE_ITALIAN
:
1561 case LANGUAGE_ITALIAN_SWISS
:
1564 case LANGUAGE_NORWEGIAN
:
1565 case LANGUAGE_NORWEGIAN_BOKMAL
:
1568 case LANGUAGE_PORTUGUESE
:
1571 case LANGUAGE_PORTUGUESE_BRAZILIAN
:
1574 case LANGUAGE_SPANISH_DATED
:
1575 case LANGUAGE_SPANISH_MEXICAN
:
1576 case LANGUAGE_SPANISH_MODERN
:
1577 case LANGUAGE_SPANISH_GUATEMALA
:
1578 case LANGUAGE_SPANISH_COSTARICA
:
1579 case LANGUAGE_SPANISH_PANAMA
:
1580 case LANGUAGE_SPANISH_DOMINICAN_REPUBLIC
:
1581 case LANGUAGE_SPANISH_VENEZUELA
:
1582 case LANGUAGE_SPANISH_COLOMBIA
:
1583 case LANGUAGE_SPANISH_PERU
:
1584 case LANGUAGE_SPANISH_ARGENTINA
:
1585 case LANGUAGE_SPANISH_ECUADOR
:
1586 case LANGUAGE_SPANISH_CHILE
:
1587 case LANGUAGE_SPANISH_URUGUAY
:
1588 case LANGUAGE_SPANISH_PARAGUAY
:
1589 case LANGUAGE_SPANISH_BOLIVIA
:
1592 case LANGUAGE_SWEDISH
:
1595 case LANGUAGE_POLISH
:
1597 case LANGUAGE_CZECH
:
1599 case LANGUAGE_SLOVENIAN
:
1601 case LANGUAGE_HUNGARIAN
:
1603 case LANGUAGE_RUSSIAN
:
1605 case LANGUAGE_SLOVAK
:
1607 case LANGUAGE_GREEK
:
1609 case LANGUAGE_TURKISH
:
1612 case LANGUAGE_CHINESE_SIMPLIFIED
:
1614 case LANGUAGE_CHINESE_TRADITIONAL
:
1616 case LANGUAGE_JAPANESE
:
1618 case LANGUAGE_KOREAN
:
1619 case LANGUAGE_KOREAN_JOHAB
:
1623 case LANGUAGE_HINDI
:
1626 case LANGUAGE_ARABIC_PRIMARY_ONLY
:
1627 case LANGUAGE_ARABIC_IRAQ
:
1628 case LANGUAGE_ARABIC_EGYPT
:
1629 case LANGUAGE_ARABIC_LIBYA
:
1630 case LANGUAGE_ARABIC_ALGERIA
:
1631 case LANGUAGE_ARABIC_MOROCCO
:
1632 case LANGUAGE_ARABIC_TUNISIA
:
1633 case LANGUAGE_ARABIC_OMAN
:
1634 case LANGUAGE_ARABIC_YEMEN
:
1635 case LANGUAGE_ARABIC_SYRIA
:
1636 case LANGUAGE_ARABIC_JORDAN
:
1637 case LANGUAGE_ARABIC_LEBANON
:
1638 case LANGUAGE_ARABIC_KUWAIT
:
1639 case LANGUAGE_ARABIC_UAE
:
1640 case LANGUAGE_ARABIC_BAHRAIN
:
1641 case LANGUAGE_ARABIC_QATAR
:
1644 case LANGUAGE_HEBREW
:
1647 case LANGUAGE_CATALAN
:
1654 else if ( nPrio
== 1 )
1658 case LANGUAGE_FRENCH_CANADIAN
:
1661 case LANGUAGE_PORTUGUESE_BRAZILIAN
:
1668 else if ( nPrio
== 2 )
1670 else if ( nPrio
== 3 )
1672 else if ( nPrio
== 4 )
1678 // -----------------------------------------------------------------------
1680 ResMgr
* ResMgr::CreateResMgr( const sal_Char
* pPrefixName
,
1681 com::sun::star::lang::Locale aLocale
)
1683 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1685 OUString
aPrefix( pPrefixName
, strlen( pPrefixName
), osl_getThreadTextEncoding() );
1687 if( ! aLocale
.Language
.getLength() )
1688 aLocale
= ResMgrContainer::get().getDefLocale();
1690 InternalResMgr
* pImp
= ResMgrContainer::get().getResMgr( aPrefix
, aLocale
);
1691 return pImp
? new ResMgr( pImp
) : NULL
;
1694 // -----------------------------------------------------------------------
1696 ResMgr
* ResMgr::SearchCreateResMgr(
1697 const sal_Char
* pPrefixName
,
1698 com::sun::star::lang::Locale
& rLocale
)
1700 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1702 OUString
aPrefix( pPrefixName
, strlen( pPrefixName
), osl_getThreadTextEncoding() );
1704 if( ! rLocale
.Language
.getLength() )
1705 rLocale
= ResMgrContainer::get().getDefLocale();
1707 InternalResMgr
* pImp
= ResMgrContainer::get().getResMgr( aPrefix
, rLocale
);
1708 return pImp
? new ResMgr( pImp
) : NULL
;
1711 // -----------------------------------------------------------------------
1713 INT16
ResMgr::ReadShort()
1715 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1717 if( pFallbackResMgr
)
1718 return pFallbackResMgr
->ReadShort();
1720 INT16 n
= GetShort( GetClass() );
1721 Increment( sizeof( INT16
) );
1725 // -----------------------------------------------------------------------
1727 INT32
ResMgr::ReadLong()
1729 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1731 if( pFallbackResMgr
)
1732 return pFallbackResMgr
->ReadLong();
1734 INT32 n
= GetLong( GetClass() );
1735 Increment( sizeof( INT32
) );
1739 // -----------------------------------------------------------------------
1741 UniString
ResMgr::ReadStringWithoutHook()
1743 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1745 if( pFallbackResMgr
)
1746 return pFallbackResMgr
->ReadStringWithoutHook();
1750 const ImpRCStack
& rTop
= aStack
[nCurStack
];
1751 if( (rTop
.Flags
& RC_NOTFOUND
) )
1753 #if OSL_DEBUG_LEVEL > 0
1754 aRet
= OUString( RTL_CONSTASCII_USTRINGPARAM( "<resource not found>" ) );
1758 Increment( GetStringWithoutHook( aRet
, (const BYTE
*)GetClass() ) );
1763 UniString
ResMgr::ReadString()
1765 UniString aRet
= ReadStringWithoutHook();
1766 if ( pImplResHookProc
)
1767 pImplResHookProc( aRet
);
1771 // -----------------------------------------------------------------------
1773 ULONG
ResMgr::GetAutoHelpId()
1775 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1777 if( pFallbackResMgr
)
1778 return pFallbackResMgr
->GetAutoHelpId();
1780 DBG_ASSERT( nCurStack
, "resource stack empty in Auto help id generation" );
1781 if( nCurStack
< 1 || nCurStack
> 2 )
1784 const ImpRCStack
*pRC
= StackTop( nCurStack
==1 ? 0 : 1 );
1786 DBG_ASSERT( pRC
->pResource
, "MM hat gesagt, dass der immer einen hat" );
1787 ULONG nGID
= pRC
->pResource
->GetId();
1789 if( !nGID
|| nGID
> 32767 )
1794 // GGGg gggg::gggg gggg::ggLL LLLl::llll llll
1795 switch( pRC
->pResource
->GetRT() ) { // maximal 7
1796 case RSC_DOCKINGWINDOW
:
1797 nHID
+= 0x20000000L
;
1799 nHID
+= 0x20000000L
;
1800 case RSC_MODELESSDIALOG
:
1801 nHID
+= 0x20000000L
;
1802 case RSC_FLOATINGWINDOW
:
1803 nHID
+= 0x20000000L
;
1804 case RSC_MODALDIALOG
:
1805 nHID
+= 0x20000000L
;
1807 nHID
+= 0x20000000L
;
1809 if( nCurStack
== 2 ) {
1811 ULONG nLID
= pRC
->pResource
->GetId();
1813 if( !nLID
|| nLID
> 511 )
1816 switch( pRC
->pResource
->GetRT() ) { // maximal 32
1817 case RSC_TABCONTROL
: nHID
|= 0x0000; break;
1818 case RSC_RADIOBUTTON
: nHID
|= 0x0200; break;
1819 case RSC_CHECKBOX
: nHID
|= 0x0400; break;
1820 case RSC_TRISTATEBOX
: nHID
|= 0x0600; break;
1821 case RSC_EDIT
: nHID
|= 0x0800; break;
1822 case RSC_MULTILINEEDIT
: nHID
|= 0x0A00; break;
1823 case RSC_MULTILISTBOX
: nHID
|= 0x0C00; break;
1824 case RSC_LISTBOX
: nHID
|= 0x0E00; break;
1825 case RSC_COMBOBOX
: nHID
|= 0x1000; break;
1826 case RSC_PUSHBUTTON
: nHID
|= 0x1200; break;
1827 case RSC_SPINFIELD
: nHID
|= 0x1400; break;
1828 case RSC_PATTERNFIELD
: nHID
|= 0x1600; break;
1829 case RSC_NUMERICFIELD
: nHID
|= 0x1800; break;
1830 case RSC_METRICFIELD
: nHID
|= 0x1A00; break;
1831 case RSC_CURRENCYFIELD
: nHID
|= 0x1C00; break;
1832 case RSC_DATEFIELD
: nHID
|= 0x1E00; break;
1833 case RSC_TIMEFIELD
: nHID
|= 0x2000; break;
1834 case RSC_IMAGERADIOBUTTON
: nHID
|= 0x2200; break;
1835 case RSC_NUMERICBOX
: nHID
|= 0x2400; break;
1836 case RSC_METRICBOX
: nHID
|= 0x2600; break;
1837 case RSC_CURRENCYBOX
: nHID
|= 0x2800; break;
1838 case RSC_DATEBOX
: nHID
|= 0x2A00; break;
1839 case RSC_TIMEBOX
: nHID
|= 0x2C00; break;
1840 case RSC_IMAGEBUTTON
: nHID
|= 0x2E00; break;
1841 case RSC_MENUBUTTON
: nHID
|= 0x3000; break;
1842 case RSC_MOREBUTTON
: nHID
|= 0x3200; break;
1857 // -----------------------------------------------------------------------
1859 void ResMgr::SetReadStringHook( ResHookProc pProc
)
1861 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1862 pImplResHookProc
= pProc
;
1865 // -----------------------------------------------------------------------
1867 ResHookProc
ResMgr::GetReadStringHook()
1869 return pImplResHookProc
;
1872 // -----------------------------------------------------------------------
1874 void ResMgr::SetDefaultLocale( const com::sun::star::lang::Locale
& rLocale
)
1876 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1877 ResMgrContainer::get().setDefLocale( rLocale
);
1880 // -----------------------------------------------------------------------
1882 const OUString
& ResMgr::GetFileName() const
1884 return pImpRes
->aFileName
;
1887 // =======================================================================
1889 SimpleResMgr::SimpleResMgr( const sal_Char
* pPrefixName
,
1890 const ::com::sun::star::lang::Locale
& rLocale
)
1892 OUString
aPrefix( pPrefixName
, strlen( pPrefixName
), osl_getThreadTextEncoding() );
1893 com::sun::star::lang::Locale
aLocale( rLocale
);
1895 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1896 if( ! aLocale
.Language
.getLength() )
1897 aLocale
= ResMgrContainer::get().getDefLocale();
1899 m_pResImpl
= ResMgrContainer::get().getResMgr( aPrefix
, aLocale
, true );
1900 DBG_ASSERT( m_pResImpl
, "SimpleResMgr::SimpleResMgr : have no impl class !" );
1903 // -----------------------------------------------------------------------
1904 SimpleResMgr::SimpleResMgr( const ::rtl::OUString
& _rPrefixName
, ::com::sun::star::lang::Locale
& _inout_Locale
)
1906 osl::Guard
<osl::Mutex
> aGuard( getResMgrMutex() );
1907 m_pResImpl
= ResMgrContainer::get().getResMgr( _rPrefixName
, _inout_Locale
, true );
1910 // -----------------------------------------------------------------------
1911 SimpleResMgr::~SimpleResMgr()
1916 // -----------------------------------------------------------------------
1917 SimpleResMgr
* SimpleResMgr::Create( const sal_Char
* pPrefixName
, com::sun::star::lang::Locale aLocale
)
1919 return new SimpleResMgr( pPrefixName
, aLocale
);
1922 // -----------------------------------------------------------------------
1923 bool SimpleResMgr::IsAvailable( RESOURCE_TYPE _resourceType
, sal_uInt32 _resourceId
)
1925 NAMESPACE_VOS(OGuard
) aGuard(m_aAccessSafety
);
1927 if ( ( RSC_STRING
!= _resourceType
) && ( RSC_RESOURCE
!= _resourceType
) )
1930 DBG_ASSERT( m_pResImpl
, "SimpleResMgr::IsAvailable: have no impl class !" );
1931 return m_pResImpl
->IsGlobalAvailable( _resourceType
, _resourceId
);
1934 // -----------------------------------------------------------------------
1935 UniString
SimpleResMgr::ReadString( sal_uInt32 nId
)
1937 NAMESPACE_VOS(OGuard
) aGuard(m_aAccessSafety
);
1939 DBG_ASSERT( m_pResImpl
, "SimpleResMgr::ReadString : have no impl class !" );
1940 // perhaps constructed with an invalid filename ?
1946 void* pResHandle
= NULL
;
1947 InternalResMgr
* pFallback
= m_pResImpl
;
1948 RSHEADER_TYPE
* pResHeader
= (RSHEADER_TYPE
*)m_pResImpl
->LoadGlobalRes( RSC_STRING
, nId
, &pResHandle
);
1951 osl::Guard
<osl::Mutex
> aGuard2( getResMgrMutex() );
1954 while( ! pResHandle
&& pFallback
)
1956 InternalResMgr
* pOldFallback
= pFallback
;
1957 pFallback
= ResMgrContainer::get().getNextFallback( pFallback
);
1958 if( pOldFallback
!= m_pResImpl
)
1959 ResMgrContainer::get().freeResMgr( pOldFallback
);
1962 // handle possible recursion
1963 if( pFallback
->aLocale
.Language
!= m_pResImpl
->aLocale
.Language
||
1964 pFallback
->aLocale
.Country
!= m_pResImpl
->aLocale
.Country
||
1965 pFallback
->aLocale
.Variant
!= m_pResImpl
->aLocale
.Variant
)
1967 pResHeader
= (RSHEADER_TYPE
*)pFallback
->LoadGlobalRes( RSC_STRING
, nId
, &pResHandle
);
1971 ResMgrContainer::get().freeResMgr( pFallback
);
1981 // ULONG nLen = pResHeader->GetLocalOff() - sizeof(RSHEADER_TYPE);
1982 ResMgr::GetString( sReturn
, (const BYTE
*)(pResHeader
+1) );
1984 // not neccessary with te current implementation which holds the string table permanently, but to be sure ....
1985 // note: pFallback cannot be NULL here and is either the fallback or m_pResImpl
1986 pFallback
->FreeGlobalRes( pResHeader
, pResHandle
);
1987 if( m_pResImpl
!= pFallback
)
1989 osl::Guard
<osl::Mutex
> aGuard2( getResMgrMutex() );
1991 ResMgrContainer::get().freeResMgr( pFallback
);
1996 // -----------------------------------------------------------------------
1998 const ::com::sun::star::lang::Locale
& SimpleResMgr::GetLocale() const
2000 DBG_ASSERT( IsValid(), "SimpleResMgr::ReadBlob: invalid, this will crash!" );
2001 return m_pResImpl
->aLocale
;
2004 // -----------------------------------------------------------------------
2006 sal_uInt32
SimpleResMgr::ReadBlob( sal_uInt32 nId
, void** pBuffer
)
2008 NAMESPACE_VOS(OGuard
) aGuard(m_aAccessSafety
);
2010 DBG_ASSERT( m_pResImpl
, "SimpleResMgr::ReadBlob : have no impl class !" );
2012 // perhaps constructed with an invalid filename ?
2013 DBG_ASSERT( pBuffer
, "SimpleResMgr::ReadBlob : invalid argument !" );
2016 void* pResHandle
= NULL
;
2017 InternalResMgr
* pFallback
= m_pResImpl
;
2018 RSHEADER_TYPE
* pResHeader
= (RSHEADER_TYPE
*)m_pResImpl
->LoadGlobalRes( RSC_RESOURCE
, nId
, &pResHandle
);
2019 DBG_ASSERT( pResHeader
, "SimpleResMgr::ReadBlob : couldn't find the resource with the given id !" );
2023 osl::Guard
<osl::Mutex
> aGuard2( getResMgrMutex() );
2026 while( ! pResHandle
&& pFallback
)
2028 InternalResMgr
* pOldFallback
= pFallback
;
2029 pFallback
= ResMgrContainer::get().getNextFallback( pFallback
);
2030 if( pOldFallback
!= m_pResImpl
)
2031 ResMgrContainer::get().freeResMgr( pOldFallback
);
2034 // handle possible recursion
2035 if( pFallback
->aLocale
.Language
!= m_pResImpl
->aLocale
.Language
||
2036 pFallback
->aLocale
.Country
!= m_pResImpl
->aLocale
.Country
||
2037 pFallback
->aLocale
.Variant
!= m_pResImpl
->aLocale
.Variant
)
2039 pResHeader
= (RSHEADER_TYPE
*)pFallback
->LoadGlobalRes( RSC_RESOURCE
, nId
, &pResHandle
);
2043 ResMgrContainer::get().freeResMgr( pFallback
);
2049 // no exception handling, this would require the locking of the solar mutex which isn't allowed within this class
2053 DBG_ASSERT( pResHandle
== NULL
, "SimpleResMgr::ReadBlob : behaviour of LoadGlobalRes changed !" );
2054 // if pResHandle is not NULL the FreeBlob wouldn't have to delete the pointer given as pBuffer, but
2055 // FreeBlob doesn't know that so it would probably crash ....
2057 sal_uInt32 nRemaining
= pResHeader
->GetLocalOff() - sizeof(RSHEADER_TYPE
);
2058 *pBuffer
= (void*)(((BYTE
*)pResHeader
) + sizeof(RSHEADER_TYPE
));
2060 // free an eventual fallback InternalResMgr
2061 if( m_pResImpl
!= pFallback
)
2063 osl::Guard
<osl::Mutex
> aGuard2( getResMgrMutex() );
2065 ResMgrContainer::get().freeResMgr( pFallback
);
2071 // -----------------------------------------------------------------------
2073 void SimpleResMgr::FreeBlob( void* pBuffer
)
2075 void* pCompleteBuffer
= (void*)(((BYTE
*)pBuffer
) - sizeof(RSHEADER_TYPE
));
2076 rtl_freeMemory(pCompleteBuffer
);