| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_tools.hxx" |
| |
| #include <string.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <vos/signal.hxx> |
| #include <tools/debug.hxx> |
| #ifndef _TABLE_HXX |
| #include <tools/table.hxx> |
| #endif |
| #include <tools/stream.hxx> |
| #include <tools/resmgr.hxx> |
| #include <tools/rc.hxx> |
| #include <tools/rcid.h> |
| #include <osl/endian.h> |
| #include <osl/process.h> |
| #include <osl/thread.h> |
| #include <osl/file.hxx> |
| #include <osl/mutex.hxx> |
| #include <rtl/ustrbuf.hxx> |
| #include <rtl/strbuf.hxx> |
| #include <tools/urlobj.hxx> |
| #include <rtl/instance.hxx> |
| #include <rtl/bootstrap.hxx> |
| #include <i18npool/mslangid.hxx> |
| #include <tools/simplerm.hxx> |
| |
| #include <tools/isofallback.hxx> |
| |
| #include <functional> |
| #include <algorithm> |
| #include <hash_map> |
| #include <list> |
| #include <set> |
| |
| #ifdef UNX |
| #define SEARCH_PATH_DELIMITER_CHAR_STRING ":" |
| #define SEARCH_PATH_DELIMITER ':' |
| #else |
| #define SEARCH_PATH_DELIMITER_CHAR_STRING ";" |
| #define SEARCH_PATH_DELIMITER ';' |
| #endif |
| |
| #define SEARCH_PATH_DELIMITER_STRING ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SEARCH_PATH_DELIMITER_CHAR_STRING ) ) |
| |
| using namespace rtl; |
| using namespace osl; |
| |
| // for thread safety |
| static osl::Mutex* pResMgrMutex = NULL; |
| static osl::Mutex& getResMgrMutex() |
| { |
| if( !pResMgrMutex ) |
| { |
| osl::Guard<osl::Mutex> aGuard( *osl::Mutex::getGlobalMutex() ); |
| if( ! pResMgrMutex ) |
| pResMgrMutex = new osl::Mutex(); |
| } |
| return *pResMgrMutex; |
| } |
| |
| struct ImpContent; |
| class InternalResMgr |
| { |
| friend class ResMgr; |
| friend class SimpleResMgr; |
| friend class ResMgrContainer; |
| |
| ImpContent * pContent; |
| sal_uInt32 nOffCorrection; |
| sal_uInt8 * pStringBlock; |
| SvStream * pStm; |
| sal_Bool bEqual2Content; |
| sal_uInt32 nEntries; |
| OUString aFileName; |
| OUString aPrefix; |
| OUString aResName; |
| bool bSingular; |
| com::sun::star::lang::Locale aLocale; |
| std::hash_map<sal_uInt64, int>* pResUseDump; |
| |
| InternalResMgr( const OUString& rFileURL, |
| const OUString& aPrefix, |
| const OUString& aResName, |
| const com::sun::star::lang::Locale& rLocale ); |
| ~InternalResMgr(); |
| sal_Bool Create(); |
| |
| sal_Bool IsGlobalAvailable( RESOURCE_TYPE nRT, sal_uInt32 nId ) const; |
| void * LoadGlobalRes( RESOURCE_TYPE nRT, sal_uInt32 nId, |
| void **pResHandle ); |
| public: |
| void FreeGlobalRes( void *, void * ); |
| |
| SvStream * GetBitmapStream( sal_uInt32 nResId ); |
| }; |
| |
| // ======================================================================= |
| |
| class ResMgrContainer |
| { |
| static ResMgrContainer* pOneInstance; |
| |
| struct ContainerElement |
| { |
| InternalResMgr* pResMgr; |
| OUString aFileURL; |
| int nRefCount; |
| int nLoadCount; |
| |
| ContainerElement() : |
| pResMgr( NULL ), |
| nRefCount( 0 ), |
| nLoadCount( 0 ) |
| {} |
| }; |
| |
| std::hash_map< OUString, ContainerElement, OUStringHash> m_aResFiles; |
| com::sun::star::lang::Locale m_aDefLocale; |
| |
| ResMgrContainer() { init(); } |
| ~ResMgrContainer(); |
| |
| void init(); |
| public: |
| |
| static ResMgrContainer& get(); |
| static void release(); |
| |
| InternalResMgr* getResMgr( const OUString& rPrefix, |
| com::sun::star::lang::Locale& rLocale, |
| bool bForceNewInstance = false |
| ); |
| InternalResMgr* getNextFallback( InternalResMgr* pResMgr ); |
| |
| void freeResMgr( InternalResMgr* pResMgr ); |
| |
| void setDefLocale( const com::sun::star::lang::Locale& rLocale ) |
| { m_aDefLocale = rLocale; } |
| const com::sun::star::lang::Locale& getDefLocale() const |
| { return m_aDefLocale; } |
| }; |
| |
| ResMgrContainer* ResMgrContainer::pOneInstance = NULL; |
| |
| ResMgrContainer& ResMgrContainer::get() |
| { |
| if( ! pOneInstance ) |
| pOneInstance = new ResMgrContainer(); |
| return *pOneInstance; |
| } |
| |
| ResMgrContainer::~ResMgrContainer() |
| { |
| for( std::hash_map< OUString, ContainerElement, OUStringHash >::iterator it = |
| m_aResFiles.begin(); it != m_aResFiles.end(); ++it ) |
| { |
| OSL_TRACE( "Resource file %s loaded %d times\n", |
| OUStringToOString( it->second.aFileURL, osl_getThreadTextEncoding() ).getStr(), |
| it->second.nLoadCount ); |
| delete it->second.pResMgr; |
| } |
| } |
| |
| void ResMgrContainer::release() |
| { |
| delete pOneInstance; |
| pOneInstance = NULL; |
| } |
| |
| void ResMgrContainer::init() |
| { |
| // get resource path |
| std::list< OUString > aDirs; |
| sal_Int32 nIndex = 0; |
| |
| // 1. fixed locations |
| rtl::OUString uri( |
| RTL_CONSTASCII_USTRINGPARAM("$OOO_BASE_DIR/program/resource")); |
| rtl::Bootstrap::expandMacros(uri); |
| aDirs.push_back(uri); |
| |
| // 2. in STAR_RESOURCEPATH |
| const sal_Char* pEnv = getenv( "STAR_RESOURCEPATH" ); |
| if( pEnv ) |
| { |
| OUString aEnvPath( OStringToOUString( OString( pEnv ), osl_getThreadTextEncoding() ) ); |
| nIndex = 0; |
| while( nIndex >= 0 ) |
| { |
| OUString aPathElement( aEnvPath.getToken( 0, SEARCH_PATH_DELIMITER, nIndex ) ); |
| if( aPathElement.getLength() ) |
| { |
| OUString aFileURL; |
| File::getFileURLFromSystemPath( aPathElement, aFileURL ); |
| aDirs.push_back( aFileURL); |
| } |
| } |
| } |
| |
| // collect all possible resource files |
| for( std::list< OUString >::const_iterator dir_it = aDirs.begin(); dir_it != aDirs.end(); ++dir_it ) |
| { |
| Directory aDir( *dir_it ); |
| if( aDir.open() == FileBase::E_None ) |
| { |
| DirectoryItem aItem; |
| while( aDir.getNextItem( aItem ) == FileBase::E_None ) |
| { |
| FileStatus aStatus(FileStatusMask_FileName); |
| if( aItem.getFileStatus( aStatus ) == FileBase::E_None ) |
| { |
| OUString aFileName = aStatus.getFileName(); |
| if( aFileName.getLength() < 5 ) |
| continue; |
| if( ! aFileName.endsWithIgnoreAsciiCaseAsciiL( ".res", 4 ) ) |
| continue; |
| OUString aResName = aFileName.copy( 0, aFileName.getLength()-4 ); |
| if( m_aResFiles.find( aResName ) != m_aResFiles.end() ) |
| continue; |
| OUStringBuffer aURL( dir_it->getLength() + aFileName.getLength() + 1 ); |
| aURL.append( *dir_it ); |
| if( !dir_it->endsWithIgnoreAsciiCaseAsciiL( "/", 1 ) ) |
| aURL.append( sal_Unicode('/') ); |
| aURL.append( aFileName ); |
| m_aResFiles[ aResName ].aFileURL = aURL.makeStringAndClear(); |
| } |
| } |
| } |
| #if OSL_DEBUG_LEVEL > 1 |
| else |
| OSL_TRACE( "opening dir %s failed\n", OUStringToOString( *dir_it, osl_getThreadTextEncoding() ).getStr() ); |
| #endif |
| } |
| #if OSL_DEBUG_LEVEL > 1 |
| for( std::hash_map< OUString, ContainerElement, OUStringHash >::const_iterator it = |
| m_aResFiles.begin(); it != m_aResFiles.end(); ++it ) |
| { |
| OSL_TRACE( "ResMgrContainer: %s -> %s\n", |
| OUStringToOString( it->first, osl_getThreadTextEncoding() ).getStr(), |
| OUStringToOString( it->second.aFileURL, osl_getThreadTextEncoding() ).getStr() ); |
| } |
| #endif |
| |
| // set default language |
| LanguageType nLang = MsLangId::getSystemUILanguage(); |
| MsLangId::convertLanguageToLocale(nLang, m_aDefLocale); |
| } |
| |
| InternalResMgr* ResMgrContainer::getResMgr( const OUString& rPrefix, |
| com::sun::star::lang::Locale& rLocale, |
| bool bForceNewInstance |
| ) |
| { |
| com::sun::star::lang::Locale aLocale( rLocale ); |
| OUStringBuffer aSearch( rPrefix.getLength() + 16 ); |
| std::hash_map< OUString, ContainerElement, OUStringHash >::iterator it = m_aResFiles.end(); |
| |
| int nTries = 0; |
| if( aLocale.Language.getLength() > 0 ) |
| nTries = 1; |
| if( aLocale.Country.getLength() > 0 ) |
| nTries = 2; |
| if( aLocale.Variant.getLength() > 0 ) |
| nTries = 3; |
| while( nTries-- ) |
| { |
| aSearch.append( rPrefix ); |
| if( nTries > -1 ) |
| { |
| aSearch.append( aLocale.Language ); |
| } |
| if( nTries > 0 ) |
| { |
| aSearch.append( sal_Unicode('-') ); |
| aSearch.append( aLocale.Country ); |
| } |
| if( nTries > 1 ) |
| { |
| aSearch.append( sal_Unicode('-') ); |
| aSearch.append( aLocale.Variant ); |
| } |
| it = m_aResFiles.find( aSearch.makeStringAndClear() ); |
| if( it != m_aResFiles.end() ) |
| { |
| // ensure InternalResMgr existance |
| if( ! it->second.pResMgr ) |
| { |
| InternalResMgr* pImp = |
| new InternalResMgr( it->second.aFileURL, rPrefix, it->first, aLocale ); |
| if( ! pImp->Create() ) |
| { |
| delete pImp; |
| continue; |
| } |
| it->second.pResMgr = pImp; |
| } |
| break; |
| } |
| if( nTries == 0 && !aLocale.Language.equalsIgnoreAsciiCaseAscii( "en" ) ) |
| { |
| // locale fallback failed |
| // fallback to en-US locale |
| nTries = 2; |
| aLocale.Language = OUString( RTL_CONSTASCII_USTRINGPARAM( "en" ) ); |
| aLocale.Country = OUString( RTL_CONSTASCII_USTRINGPARAM( "US" ) ); |
| aLocale.Variant = OUString(); |
| } |
| } |
| // try if there is anything with this prefix at all |
| if( it == m_aResFiles.end() ) |
| { |
| aLocale = com::sun::star::lang::Locale(); |
| it = m_aResFiles.find( rPrefix ); |
| if( it == m_aResFiles.end() ) |
| { |
| for( it = m_aResFiles.begin(); it != m_aResFiles.end(); ++it ) |
| { |
| if( it->first.matchIgnoreAsciiCase( rPrefix ) ) |
| { |
| // ensure InternalResMgr existance |
| if( ! it->second.pResMgr ) |
| { |
| InternalResMgr* pImp = |
| new InternalResMgr( it->second.aFileURL, |
| rPrefix, |
| it->first, |
| aLocale ); |
| if( ! pImp->Create() ) |
| { |
| delete pImp; |
| continue; |
| } |
| it->second.pResMgr = pImp; |
| } |
| // try to guess locale |
| sal_Int32 nIndex = rPrefix.getLength(); |
| aLocale.Language = it->first.getToken( 0, '-', nIndex ); |
| if( nIndex > 0 ) |
| aLocale.Country = it->first.getToken( 0, '-', nIndex ); |
| if( nIndex > 0 ) |
| aLocale.Variant = it->first.getToken( 0, '-', nIndex ); |
| break; |
| } |
| } |
| } |
| } |
| // give up |
| if( it == m_aResFiles.end() ) |
| { |
| OUStringBuffer sKey = rPrefix; |
| sKey.append( rLocale.Language ); |
| if( rLocale.Country.getLength() ) |
| { |
| sKey.append( sal_Unicode('-') ); |
| sKey.append( rLocale.Country ); |
| } |
| if( rLocale.Variant.getLength() ) |
| { |
| sKey.append( sal_Unicode('-') ); |
| sKey.append( rLocale.Variant ); |
| } // if( aLocale.Variant.getLength() ) |
| ::rtl::OUString sURL = sKey.makeStringAndClear(); |
| sURL += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".res")); |
| if ( m_aResFiles.find(sURL) == m_aResFiles.end() ) |
| { |
| m_aResFiles[ sURL ].aFileURL = sURL; |
| return getResMgr(rPrefix,rLocale,bForceNewInstance); |
| } // if ( m_aResFiles.find(sURL) == m_aResFiles.end() ) |
| return NULL; |
| } |
| |
| rLocale = aLocale; |
| // at this point it->second.pResMgr must be filled either by creating a new one |
| // (then the refcount is still 0) or because we already had one |
| InternalResMgr* pImp = it->second.pResMgr; |
| |
| if( it->second.nRefCount == 0 ) |
| it->second.nLoadCount++; |
| |
| // for SimpleResMgr |
| if( bForceNewInstance ) |
| { |
| if( it->second.nRefCount == 0 ) |
| { |
| // shortcut: the match algorithm already created the InternalResMgr |
| // take it instead of creating yet another one |
| it->second.pResMgr = NULL; |
| pImp->bSingular = true; |
| } |
| else |
| { |
| pImp = new InternalResMgr( it->second.aFileURL, rPrefix, it->first, aLocale ); |
| pImp->bSingular = true; |
| if( !pImp->Create() ) |
| { |
| delete pImp; |
| pImp = NULL; |
| } |
| else |
| it->second.nLoadCount++; |
| } |
| } |
| else |
| it->second.nRefCount++; |
| |
| return pImp; |
| } |
| |
| InternalResMgr* ResMgrContainer::getNextFallback( InternalResMgr* pMgr ) |
| { |
| com::sun::star::lang::Locale aLocale = pMgr->aLocale; |
| if( aLocale.Variant.getLength() ) |
| aLocale.Variant = OUString(); |
| else if( aLocale.Country.getLength() ) |
| aLocale.Country = OUString(); |
| else if( ! aLocale.Language.equalsIgnoreAsciiCaseAscii( "en" ) ) |
| { |
| aLocale.Language = OUString( RTL_CONSTASCII_USTRINGPARAM( "en" ) ); |
| aLocale.Country = OUString( RTL_CONSTASCII_USTRINGPARAM( "US" ) ); |
| } |
| InternalResMgr* pNext = getResMgr( pMgr->aPrefix, aLocale, pMgr->bSingular ); |
| // prevent recursion |
| if( pNext == pMgr || pNext->aResName.equals( pMgr->aResName ) ) |
| { |
| if( pNext->bSingular ) |
| delete pNext; |
| pNext = NULL; |
| } |
| return pNext; |
| } |
| |
| void ResMgrContainer::freeResMgr( InternalResMgr* pResMgr ) |
| { |
| if( pResMgr->bSingular ) |
| delete pResMgr; |
| else |
| { |
| std::hash_map< OUString, ContainerElement, OUStringHash >::iterator it = |
| m_aResFiles.find( pResMgr->aResName ); |
| if( it != m_aResFiles.end() ) |
| { |
| DBG_ASSERT( it->second.nRefCount > 0, "InternalResMgr freed too often" ); |
| if( it->second.nRefCount > 0 ) |
| it->second.nRefCount--; |
| if( it->second.nRefCount == 0 ) |
| { |
| delete it->second.pResMgr; |
| it->second.pResMgr = NULL; |
| } |
| } |
| } |
| } |
| |
| // ======================================================================= |
| |
| void Resource::TestRes() |
| { |
| if( m_pResMgr ) |
| m_pResMgr->TestStack( this ); |
| } |
| |
| struct ImpContent |
| { |
| sal_uInt64 nTypeAndId; |
| sal_uInt32 nOffset; |
| }; |
| |
| struct ImpContentLessCompare : public ::std::binary_function< ImpContent, ImpContent, bool> |
| { |
| inline bool operator() (const ImpContent& lhs, const ImpContent& rhs) const |
| { |
| return lhs.nTypeAndId < rhs.nTypeAndId; |
| } |
| }; |
| |
| struct ImpContentMixLessCompare : public ::std::binary_function< ImpContent, sal_uInt64, bool> |
| { |
| inline bool operator() (const ImpContent& lhs, const sal_uInt64& rhs) const |
| { |
| return lhs.nTypeAndId < rhs; |
| } |
| inline bool operator() (const sal_uInt64& lhs, const ImpContent& rhs) const |
| { |
| return lhs < rhs.nTypeAndId; |
| } |
| }; |
| |
| |
| // ======================================================================= |
| |
| static ResHookProc pImplResHookProc = 0; |
| |
| // ======================================================================= |
| |
| SvStream * InternalResMgr::GetBitmapStream( sal_uInt32 nId ) |
| { |
| // Anfang der Strings suchen |
| ImpContent * pFind = ::std::lower_bound(pContent, |
| pContent + nEntries, |
| ((sal_uInt64(RT_SYS_BITMAP) << 32) | nId), |
| ImpContentMixLessCompare()); |
| if ( (pFind != (pContent + nEntries)) && (pFind->nTypeAndId == ((sal_uInt64(RT_SYS_BITMAP) << 32) | nId)) ) |
| { |
| pStm->Seek( pFind->nOffset ); |
| return pStm; |
| } |
| return NULL; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| InternalResMgr::InternalResMgr( const OUString& rFileURL, |
| const OUString& rPrefix, |
| const OUString& rResName, |
| const com::sun::star::lang::Locale& rLocale ) |
| : pContent( NULL ) |
| , pStringBlock( NULL ) |
| , pStm( NULL ) |
| , bEqual2Content( sal_True ) |
| , nEntries( 0 ) |
| , aFileName( rFileURL ) |
| , aPrefix( rPrefix ) |
| , aResName( rResName ) |
| , bSingular( false ) |
| , aLocale( rLocale ) |
| , pResUseDump( 0 ) |
| { |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| InternalResMgr::~InternalResMgr() |
| { |
| rtl_freeMemory(pContent); |
| rtl_freeMemory(pStringBlock); |
| delete pStm; |
| |
| #ifdef DBG_UTIL |
| if( pResUseDump ) |
| { |
| const sal_Char* pLogFile = getenv( "STAR_RESOURCE_LOGGING" ); |
| if ( pLogFile ) |
| { |
| SvFileStream aStm( UniString( pLogFile, RTL_TEXTENCODING_ASCII_US ), STREAM_WRITE ); |
| aStm.Seek( STREAM_SEEK_TO_END ); |
| ByteString aLine( "FileName: " ); |
| aLine.Append( ByteString( OUStringToOString( aFileName, RTL_TEXTENCODING_UTF8 ) ) ); |
| aStm.WriteLine( aLine ); |
| |
| for( std::hash_map<sal_uInt64, int>::const_iterator it = pResUseDump->begin(); |
| it != pResUseDump->end(); ++it ) |
| { |
| sal_uInt64 nKeyId = it->first; |
| aLine.Assign( "Type/Id: " ); |
| aLine.Append( ByteString::CreateFromInt32( sal::static_int_cast< sal_Int32 >((nKeyId >> 32) & 0xFFFFFFFF) ) ); |
| aLine.Append( '/' ); |
| aLine.Append( ByteString::CreateFromInt32( sal::static_int_cast< sal_Int32 >(nKeyId & 0xFFFFFFFF) ) ); |
| aStm.WriteLine( aLine ); |
| } |
| } |
| } |
| #endif |
| |
| delete pResUseDump; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| |
| sal_Bool InternalResMgr::Create() |
| { |
| ResMgrContainer::get(); |
| sal_Bool bDone = sal_False; |
| |
| pStm = new SvFileStream( aFileName, (STREAM_READ | STREAM_SHARE_DENYWRITE | STREAM_NOCREATE) ); |
| if( pStm->GetError() == 0 ) |
| { |
| sal_Int32 lContLen = 0; |
| |
| pStm->Seek( STREAM_SEEK_TO_END ); |
| /* |
| if( ( pInternalResMgr->pHead = (RSHEADER_TYPE *)mmap( 0, nResourceFileSize, |
| PROT_READ, MAP_PRIVATE, |
| fRes, 0 ) ) != (RSHEADER_TYPE *)-1) |
| */ |
| pStm->SeekRel( - (int)sizeof( lContLen ) ); |
| pStm->Read( &lContLen, sizeof( lContLen ) ); |
| // is bigendian, swab to the right endian |
| lContLen = ResMgr::GetLong( &lContLen ); |
| pStm->SeekRel( -lContLen ); |
| // allocate stored ImpContent data (12 bytes per unit) |
| sal_uInt8* pContentBuf = (sal_uInt8*)rtl_allocateMemory( lContLen ); |
| pStm->Read( pContentBuf, lContLen ); |
| // allocate ImpContent space (sizeof(ImpContent) per unit, not necessarily 12) |
| pContent = (ImpContent *)rtl_allocateMemory( sizeof(ImpContent)*lContLen/12 ); |
| // Auf die Anzahl der ImpContent k�rzen |
| nEntries = (sal_uInt32)lContLen / 12; |
| bEqual2Content = sal_True; // Die Daten der Resourcen liegen |
| // genauso wie das Inhaltsverzeichnis |
| sal_Bool bSorted = sal_True; |
| if( nEntries ) |
| { |
| #ifdef DBG_UTIL |
| const sal_Char* pLogFile = getenv( "STAR_RESOURCE_LOGGING" ); |
| if ( pLogFile ) |
| { |
| pResUseDump = new std::hash_map<sal_uInt64, int>; |
| for( sal_uInt32 i = 0; i < nEntries; ++i ) |
| (*pResUseDump)[pContent[i].nTypeAndId] = 1; |
| } |
| #endif |
| // swap the content to the right endian |
| pContent[0].nTypeAndId = ResMgr::GetUInt64( pContentBuf ); |
| pContent[0].nOffset = ResMgr::GetLong( pContentBuf+8 ); |
| sal_uInt32 nCount = nEntries - 1; |
| for( sal_uInt32 i = 0,j=1; i < nCount; ++i,++j ) |
| { |
| // swap the content to the right endian |
| pContent[j].nTypeAndId = ResMgr::GetUInt64( pContentBuf + (12*j) ); |
| pContent[j].nOffset = ResMgr::GetLong( pContentBuf + (12*j+8) ); |
| if( pContent[i].nTypeAndId >= pContent[j].nTypeAndId ) |
| bSorted = sal_False; |
| if( (pContent[i].nTypeAndId & 0xFFFFFFFF00000000LL) == (pContent[j].nTypeAndId & 0xFFFFFFFF00000000LL) |
| && pContent[i].nOffset >= pContent[j].nOffset ) |
| bEqual2Content = sal_False; |
| } |
| } |
| rtl_freeMemory( pContentBuf ); |
| #ifndef OS2 |
| OSL_ENSURE( bSorted, "content not sorted" ); |
| #endif |
| OSL_ENSURE( bEqual2Content, "resource structure wrong" ); |
| if( !bSorted ) |
| ::std::sort(pContent,pContent+nEntries,ImpContentLessCompare()); |
| // qsort( pContent, nEntries, sizeof( ImpContent ), Compare ); |
| |
| bDone = sal_True; |
| } |
| |
| return bDone; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| sal_Bool InternalResMgr::IsGlobalAvailable( RESOURCE_TYPE nRT, sal_uInt32 nId ) const |
| { |
| // Anfang der Strings suchen |
| sal_uInt64 nValue = ((sal_uInt64(nRT) << 32) | nId); |
| ImpContent * pFind = ::std::lower_bound(pContent, |
| pContent + nEntries, |
| nValue, |
| ImpContentMixLessCompare()); |
| return (pFind != (pContent + nEntries)) && (pFind->nTypeAndId == nValue); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| void* InternalResMgr::LoadGlobalRes( RESOURCE_TYPE nRT, sal_uInt32 nId, |
| void **pResHandle ) |
| { |
| #ifdef DBG_UTIL |
| if( pResUseDump ) |
| pResUseDump->erase( (sal_uInt64(nRT) << 32) | nId ); |
| #endif |
| // Anfang der Strings suchen |
| sal_uInt64 nValue = ((sal_uInt64(nRT) << 32) | nId); |
| ImpContent* pEnd = (pContent + nEntries); |
| ImpContent* pFind = ::std::lower_bound( pContent, |
| pEnd, |
| nValue, |
| ImpContentMixLessCompare()); |
| if( pFind && (pFind != pEnd) && (pFind->nTypeAndId == nValue) ) |
| { |
| if( nRT == RSC_STRING && bEqual2Content ) |
| { |
| // String Optimierung |
| if( !pStringBlock ) |
| { |
| // Anfang der Strings suchen |
| ImpContent * pFirst = pFind; |
| ImpContent * pLast = pFirst; |
| while( pFirst > pContent && ((pFirst -1)->nTypeAndId >> 32) == RSC_STRING ) |
| --pFirst; |
| while( pLast < pEnd && (pLast->nTypeAndId >> 32) == RSC_STRING ) |
| ++pLast; |
| nOffCorrection = pFirst->nOffset; |
| sal_uInt32 nSize; |
| --pLast; |
| pStm->Seek( pLast->nOffset ); |
| RSHEADER_TYPE aHdr; |
| pStm->Read( &aHdr, sizeof( aHdr ) ); |
| nSize = pLast->nOffset + aHdr.GetGlobOff() - nOffCorrection; |
| pStringBlock = (sal_uInt8*)rtl_allocateMemory( nSize ); |
| pStm->Seek( pFirst->nOffset ); |
| pStm->Read( pStringBlock, nSize ); |
| } |
| *pResHandle = pStringBlock; |
| return (sal_uInt8*)pStringBlock + pFind->nOffset - nOffCorrection; |
| } // if( nRT == RSC_STRING && bEqual2Content ) |
| else |
| { |
| *pResHandle = 0; |
| RSHEADER_TYPE aHeader; |
| pStm->Seek( pFind->nOffset ); |
| pStm->Read( &aHeader, sizeof( RSHEADER_TYPE ) ); |
| void * pRes = rtl_allocateMemory( aHeader.GetGlobOff() ); |
| memcpy( pRes, &aHeader, sizeof( RSHEADER_TYPE ) ); |
| pStm->Read( (sal_uInt8*)pRes + sizeof( RSHEADER_TYPE ), |
| aHeader.GetGlobOff() - sizeof( RSHEADER_TYPE ) ); |
| return pRes; |
| } |
| } // if( pFind && (pFind != pEnd) && (pFind->nTypeAndId == nValue) ) |
| *pResHandle = 0; |
| //Resource holen |
| return NULL; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| void InternalResMgr::FreeGlobalRes( void * pResHandle, void * pResource ) |
| { |
| if ( !pResHandle ) |
| // REsource wurde extra allokiert |
| rtl_freeMemory(pResource); |
| } |
| |
| // ======================================================================= |
| |
| #ifdef DBG_UTIL |
| |
| UniString GetTypeRes_Impl( const ResId& rTypeId ) |
| { |
| // Funktion verlassen, falls Resourcefehler in dieser Funktion |
| static int bInUse = sal_False; |
| UniString aTypStr( UniString::CreateFromInt32( rTypeId.GetId() ) ); |
| |
| if ( !bInUse ) |
| { |
| bInUse = sal_True; |
| |
| ResId aResId( sal_uInt32(RSCVERSION_ID), *rTypeId.GetResMgr() ); |
| aResId.SetRT( RSC_VERSIONCONTROL ); |
| |
| if ( rTypeId.GetResMgr()->GetResource( aResId ) ) |
| { |
| rTypeId.SetRT( RSC_STRING ); |
| if ( rTypeId.GetResMgr()->IsAvailable( rTypeId ) ) |
| { |
| aTypStr = UniString( rTypeId ); |
| // Versions Resource Klassenzeiger ans Ende setzen |
| rTypeId.GetResMgr()->Increment( sizeof( RSHEADER_TYPE ) ); |
| } |
| } |
| bInUse = sal_False; |
| } |
| |
| return aTypStr; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| void ResMgr::RscError_Impl( const sal_Char* pMessage, ResMgr* pResMgr, |
| RESOURCE_TYPE nRT, sal_uInt32 nId, |
| std::vector< ImpRCStack >& rResStack, int nDepth ) |
| { |
| // create a separate ResMgr with its own stack |
| // first get a second reference of the InternalResMgr |
| InternalResMgr* pImp = |
| ResMgrContainer::get().getResMgr( pResMgr->pImpRes->aPrefix, |
| pResMgr->pImpRes->aLocale, |
| true ); |
| |
| ResMgr* pNewResMgr = new ResMgr( pImp ); |
| |
| ByteString aStr = OUStringToOString( pResMgr->GetFileName(), RTL_TEXTENCODING_UTF8 ); |
| if ( aStr.Len() ) |
| aStr += '\n'; |
| |
| aStr.Append( "Class: " ); |
| aStr.Append( ByteString( GetTypeRes_Impl( ResId( nRT, *pNewResMgr ) ), RTL_TEXTENCODING_UTF8 ) ); |
| aStr.Append( ", Id: " ); |
| aStr.Append( ByteString::CreateFromInt32( (long)nId ) ); |
| aStr.Append( ". " ); |
| aStr.Append( pMessage ); |
| |
| aStr.Append( "\nResource Stack\n" ); |
| while( nDepth > 0 ) |
| { |
| aStr.Append( "Class: " ); |
| aStr.Append( ByteString( GetTypeRes_Impl( ResId( rResStack[nDepth].pResource->GetRT(), *pNewResMgr ) ), RTL_TEXTENCODING_UTF8 ) ); |
| aStr.Append( ", Id: " ); |
| aStr.Append( ByteString::CreateFromInt32( (long)rResStack[nDepth].pResource->GetId() ) ); |
| nDepth--; |
| } |
| |
| // clean up |
| delete pNewResMgr; |
| |
| DBG_ERROR( aStr.GetBuffer() ); |
| } |
| |
| #endif |
| |
| // ======================================================================= |
| |
| static void RscException_Impl() |
| { |
| switch ( vos::OSignalHandler::raise( OSL_SIGNAL_USER_RESOURCEFAILURE, (void*)"" ) ) |
| { |
| case vos::OSignalHandler::TAction_CallNextHandler: |
| abort(); |
| |
| case vos::OSignalHandler::TAction_Ignore: |
| return; |
| |
| case vos::OSignalHandler::TAction_AbortApplication: |
| abort(); |
| |
| case vos::OSignalHandler::TAction_KillApplication: |
| exit(-1); |
| } |
| } |
| |
| // ======================================================================= |
| |
| void ImpRCStack::Init( ResMgr* pMgr, const Resource* pObj, sal_uInt32 Id ) |
| { |
| pResource = NULL; |
| pClassRes = NULL; |
| Flags = RC_NOTYPE; |
| aResHandle = NULL; |
| pResObj = pObj; |
| nId = Id & ~RSC_DONTRELEASE; //TLX: Besser Init aendern |
| pResMgr = pMgr; |
| if ( !(Id & RSC_DONTRELEASE) ) |
| Flags |= RC_AUTORELEASE; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| void ImpRCStack::Clear() |
| { |
| pResource = NULL; |
| pClassRes = NULL; |
| Flags = RC_NOTYPE; |
| aResHandle = NULL; |
| pResObj = NULL; |
| nId = 0; |
| pResMgr = NULL; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| static RSHEADER_TYPE* LocalResource( const ImpRCStack* pStack, |
| RESOURCE_TYPE nRTType, |
| sal_uInt32 nId ) |
| { |
| // Gibt die Position der Resource zurueck, wenn sie gefunden wurde. |
| // Ansonsten gibt die Funktion Null zurueck. |
| RSHEADER_TYPE* pTmp; // Zeiger auf Kind-Resourceobjekte |
| RSHEADER_TYPE* pEnd; // Zeiger auf das Ende der Resource |
| |
| if ( pStack->pResource && pStack->pClassRes ) |
| { |
| pTmp = (RSHEADER_TYPE*) |
| ((sal_uInt8*)pStack->pResource + pStack->pResource->GetLocalOff()); |
| pEnd = (RSHEADER_TYPE*) |
| ((sal_uInt8*)pStack->pResource + pStack->pResource->GetGlobOff()); |
| while ( pTmp != pEnd ) |
| { |
| if ( pTmp->GetRT() == nRTType && pTmp->GetId() == nId ) |
| return pTmp; |
| pTmp = (RSHEADER_TYPE*)((sal_uInt8*)pTmp + pTmp->GetGlobOff()); |
| } |
| } |
| |
| return NULL; |
| } |
| |
| // ======================================================================= |
| |
| void* ResMgr::pEmptyBuffer = NULL; |
| |
| void* ResMgr::getEmptyBuffer() |
| { |
| if( ! pEmptyBuffer ) |
| pEmptyBuffer = rtl_allocateZeroMemory( 1024 ); |
| return pEmptyBuffer; |
| } |
| |
| void ResMgr::DestroyAllResMgr() |
| { |
| { |
| osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); |
| if( pEmptyBuffer ) |
| { |
| rtl_freeMemory( pEmptyBuffer ); |
| pEmptyBuffer = NULL; |
| } |
| ResMgrContainer::release(); |
| } |
| delete pResMgrMutex; |
| pResMgrMutex = NULL; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| void ResMgr::Init( const OUString& rFileName ) |
| { |
| (void) rFileName; // avoid warning about unused parameter |
| osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); |
| |
| if ( !pImpRes ) |
| { |
| #ifdef DBG_UTIL |
| ByteString aStr( "Resourcefile not found:\n" ); |
| aStr += ByteString( OUStringToOString( rFileName, RTL_TEXTENCODING_UTF8 ) ); |
| DBG_ERROR( aStr.GetBuffer() ); |
| #endif |
| RscException_Impl(); |
| } |
| #ifdef DBG_UTIL |
| else |
| { |
| void* aResHandle = 0; // Hilfvariable fuer Resource |
| void* pVoid; // Zeiger auf die Resource |
| |
| pVoid = pImpRes->LoadGlobalRes( RSC_VERSIONCONTROL, RSCVERSION_ID, |
| &aResHandle ); |
| if ( pVoid ) |
| pImpRes->FreeGlobalRes( aResHandle, pVoid ); |
| else |
| { |
| ByteString aStr( "Wrong version:\n" ); |
| aStr += ByteString( OUStringToOString( pImpRes->aFileName, RTL_TEXTENCODING_UTF8 ) ); |
| DbgError( aStr.GetBuffer() ); |
| } |
| } |
| #endif |
| nCurStack = -1; |
| aStack.clear(); |
| pFallbackResMgr = pOriginalResMgr = NULL; |
| incStack(); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| ResMgr::ResMgr( InternalResMgr * pImpMgr ) |
| { |
| pImpRes = pImpMgr; |
| Init( pImpMgr->aFileName ); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| ResMgr::~ResMgr() |
| { |
| osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); |
| |
| ResMgrContainer::get().freeResMgr( pImpRes ); |
| |
| // clean up possible left rc stack frames |
| while( nCurStack > 0 ) |
| { |
| if( ( aStack[nCurStack].Flags & (RC_GLOBAL | RC_NOTFOUND) ) == RC_GLOBAL ) |
| pImpRes->FreeGlobalRes( aStack[nCurStack].aResHandle, |
| aStack[nCurStack].pResource ); |
| nCurStack--; |
| } |
| } |
| |
| |
| void ResMgr::incStack() |
| { |
| nCurStack++; |
| if( nCurStack >= int(aStack.size()) ) |
| aStack.push_back( ImpRCStack() ); |
| aStack[nCurStack].Clear(); |
| |
| DBG_ASSERT( nCurStack < 32, "Resource stack unreasonably large" ); |
| } |
| |
| void ResMgr::decStack() |
| { |
| DBG_ASSERT( nCurStack > 0, "resource stack underrun !" ); |
| if( (aStack[nCurStack].Flags & RC_FALLBACK_UP) ) |
| { |
| nCurStack--; |
| // warning: this will delete *this, see below |
| pOriginalResMgr->decStack(); |
| } |
| else |
| { |
| ImpRCStack& rTop = aStack[nCurStack]; |
| if( (rTop.Flags & RC_FALLBACK_DOWN) ) |
| { |
| #if OSL_DEBUG_LEVEL > 1 |
| OSL_TRACE( "returning from fallback %s\n", |
| OUStringToOString(pFallbackResMgr->GetFileName(), osl_getThreadTextEncoding() ).getStr() ); |
| #endif |
| delete pFallbackResMgr; |
| pFallbackResMgr = NULL; |
| } |
| nCurStack--; |
| } |
| } |
| |
| #ifdef DBG_UTIL |
| |
| void ResMgr::TestStack( const Resource* pResObj ) |
| { |
| osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); |
| |
| if ( DbgIsResource() ) |
| { |
| for( int i = 1; i <= nCurStack; ++i ) |
| { |
| if ( aStack[i].pResObj == pResObj ) |
| { |
| #ifdef DBG_UTIL |
| RscError_Impl( "Resource not freed! ", this, |
| aStack[i].pResource->GetRT(), |
| aStack[i].pResource->GetId(), |
| aStack, i-1 ); |
| #endif |
| } |
| } |
| } |
| } |
| |
| #else |
| |
| void ResMgr::TestStack( const Resource* ) |
| { |
| } |
| |
| #endif |
| |
| // ----------------------------------------------------------------------- |
| sal_Bool ResMgr::IsAvailable( const ResId& rId, const Resource* pResObj ) const |
| { |
| osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); |
| |
| sal_Bool bAvailable = sal_False; |
| RSHEADER_TYPE* pClassRes = rId.GetpResource(); |
| RESOURCE_TYPE nRT = rId.GetRT2(); |
| sal_uInt32 nId = rId.GetId(); |
| const ResMgr* pMgr = rId.GetResMgr(); |
| |
| if ( !pMgr ) |
| pMgr = this; |
| |
| if( pMgr->pFallbackResMgr ) |
| { |
| ResId aId( rId ); |
| aId.SetResMgr( NULL ); |
| return pMgr->pFallbackResMgr->IsAvailable( aId, pResObj ); |
| } |
| |
| if ( !pResObj || pResObj == pMgr->aStack[pMgr->nCurStack].pResObj ) |
| { |
| if ( !pClassRes ) |
| pClassRes = LocalResource( &pMgr->aStack[pMgr->nCurStack], nRT, nId ); |
| if ( pClassRes ) |
| { |
| if ( pClassRes->GetRT() == nRT ) |
| bAvailable = sal_True; |
| } |
| } |
| |
| // vieleicht globale Resource |
| if ( !pClassRes ) |
| bAvailable = pMgr->pImpRes->IsGlobalAvailable( nRT, nId ); |
| |
| return bAvailable; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| void* ResMgr::GetClass() |
| { |
| osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); |
| |
| if( pFallbackResMgr ) |
| return pFallbackResMgr->GetClass(); |
| |
| return aStack[nCurStack].pClassRes; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| sal_Bool ResMgr::GetResource( const ResId& rId, const Resource* pResObj ) |
| { |
| osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); |
| |
| if( pFallbackResMgr ) |
| { |
| ResId aId( rId ); |
| aId.SetResMgr( NULL ); |
| return pFallbackResMgr->GetResource( aId, pResObj ); |
| } |
| |
| ResMgr* pMgr = rId.GetResMgr(); |
| if ( pMgr && (this != pMgr) ) |
| return pMgr->GetResource( rId, pResObj ); |
| |
| // normally Increment will pop the context; this is |
| // not possible in RC_NOTFOUND case, so pop a frame here |
| ImpRCStack* pTop = &aStack[nCurStack]; |
| if( (pTop->Flags & RC_NOTFOUND) ) |
| { |
| decStack(); |
| } |
| |
| RSHEADER_TYPE* pClassRes = rId.GetpResource(); |
| RESOURCE_TYPE nRT = rId.GetRT2(); |
| sal_uInt32 nId = rId.GetId(); |
| |
| incStack(); |
| pTop = &aStack[nCurStack]; |
| pTop->Init( pMgr, pResObj, nId | |
| (rId.IsAutoRelease() ? 0 : RSC_DONTRELEASE) ); |
| |
| if ( pClassRes ) |
| { |
| if ( pClassRes->GetRT() == nRT ) |
| pTop->pClassRes = pClassRes; |
| else |
| { |
| #ifdef DBG_UTIL |
| RscError_Impl( "Different class and resource type!", |
| this, nRT, nId, aStack, nCurStack-1 ); |
| #endif |
| pTop->Flags |= RC_NOTFOUND; |
| pTop->pClassRes = getEmptyBuffer(); |
| pTop->pResource = (RSHEADER_TYPE*)pTop->pClassRes; |
| return sal_False; |
| } |
| } |
| else |
| { |
| OSL_ENSURE( nCurStack > 0, "stack of 1 to shallow" ); |
| pTop->pClassRes = LocalResource( &aStack[nCurStack-1], nRT, nId ); |
| } |
| |
| if ( pTop->pClassRes ) |
| // lokale Resource, nicht system Resource |
| pTop->pResource = (RSHEADER_TYPE *)pTop->pClassRes; |
| else |
| { |
| pTop->pClassRes = pImpRes->LoadGlobalRes( nRT, nId, &pTop->aResHandle ); |
| if ( pTop->pClassRes ) |
| { |
| pTop->Flags |= RC_GLOBAL; |
| pTop->pResource = (RSHEADER_TYPE *)pTop->pClassRes; |
| } |
| else |
| { |
| // try to get a fallback resource |
| pFallbackResMgr = CreateFallbackResMgr( rId, pResObj ); |
| if( pFallbackResMgr ) |
| { |
| pTop->Flags |= RC_FALLBACK_DOWN; |
| #ifdef DBG_UTIL |
| ByteString aMess( "found resource " ); |
| aMess.Append( ByteString::CreateFromInt32( nId ) ); |
| aMess.Append( " in fallback " ); |
| aMess.Append( ByteString( OUStringToOString( pFallbackResMgr->GetFileName(), osl_getThreadTextEncoding() ) ) ); |
| aMess.Append( "\n" ); |
| RscError_Impl( aMess.GetBuffer(), |
| this, nRT, nId, aStack, nCurStack-1 ); |
| #endif |
| } |
| else |
| { |
| #ifdef DBG_UTIL |
| RscError_Impl( "Cannot load resource! ", |
| this, nRT, nId, aStack, nCurStack-1 ); |
| #endif |
| pTop->Flags |= RC_NOTFOUND; |
| pTop->pClassRes = getEmptyBuffer(); |
| pTop->pResource = (RSHEADER_TYPE*)pTop->pClassRes; |
| return sal_False; |
| } |
| } |
| } |
| |
| return sal_True; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| void * ResMgr::GetResourceSkipHeader( const ResId& rResId, ResMgr ** ppResMgr ) |
| { |
| osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); |
| |
| DBG_ASSERT( rResId.GetResMgr(), "illegal ResId without ResMgr" ); |
| *ppResMgr = rResId.GetResMgr(); |
| if( *ppResMgr ) |
| { |
| (*ppResMgr)->GetResource( rResId ); |
| (*ppResMgr)->Increment( sizeof( RSHEADER_TYPE ) ); |
| return (*ppResMgr)->GetClass(); |
| } |
| return getEmptyBuffer(); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| void ResMgr::PopContext( const Resource* pResObj ) |
| { |
| osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); |
| |
| if( pFallbackResMgr ) |
| { |
| pFallbackResMgr->PopContext( pResObj ); |
| return; |
| } |
| |
| #ifdef DBG_UTIL |
| if ( DbgIsResource() ) |
| { |
| if ( (aStack[nCurStack].pResObj != pResObj) || nCurStack == 0 ) |
| { |
| RscError_Impl( "Cannot free resource! ", this, |
| RSC_NOTYPE, 0, aStack, nCurStack ); |
| } |
| } |
| #endif |
| |
| if ( nCurStack > 0 ) |
| { |
| ImpRCStack* pTop = &aStack[nCurStack]; |
| #ifdef DBG_UTIL |
| if ( DbgIsResource() && !(pTop->Flags & RC_NOTFOUND) ) |
| { |
| void* pRes = (sal_uInt8*)pTop->pResource + |
| pTop->pResource->GetLocalOff(); |
| |
| if ( pTop->pClassRes != pRes ) |
| { |
| RscError_Impl( "Classpointer not at the end!", |
| this, pTop->pResource->GetRT(), |
| pTop->pResource->GetId(), |
| aStack, nCurStack-1 ); |
| } |
| } |
| #endif |
| |
| // Resource freigeben |
| if( (pTop->Flags & (RC_GLOBAL | RC_NOTFOUND)) == RC_GLOBAL ) |
| // kann auch Fremd-Ressource sein |
| pImpRes->FreeGlobalRes( pTop->aResHandle, pTop->pResource ); |
| decStack(); |
| } |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| RSHEADER_TYPE* ResMgr::CreateBlock( const ResId& rId ) |
| { |
| osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); |
| |
| if( pFallbackResMgr ) |
| { |
| ResId aId( rId ); |
| aId.SetResMgr( NULL ); |
| return pFallbackResMgr->CreateBlock( aId ); |
| } |
| |
| RSHEADER_TYPE* pHeader = NULL; |
| if ( GetResource( rId ) ) |
| { |
| // Der Zeiger steht am Anfang, deswegen zeigt der Klassen-Pointer |
| // auf den Header und die restliche Groesse ist die Gesammte. |
| pHeader = (RSHEADER_TYPE*)rtl_allocateMemory( GetRemainSize() ); |
| memcpy( pHeader, GetClass(), GetRemainSize() ); |
| Increment( pHeader->GetLocalOff() ); //ans Ende setzen |
| if ( pHeader->GetLocalOff() != pHeader->GetGlobOff() ) |
| // Hat Sub-Ressourcen, deshalb extra freigeben |
| PopContext(); |
| } |
| |
| return pHeader; |
| } |
| |
| // ------------------------------------------------------------------ |
| |
| sal_Int16 ResMgr::GetShort( void * pShort ) |
| { |
| return ((*((sal_uInt8*)pShort + 0) << 8) | |
| (*((sal_uInt8*)pShort + 1) << 0) ); |
| } |
| |
| // ------------------------------------------------------------------ |
| |
| sal_Int32 ResMgr::GetLong( void * pLong ) |
| { |
| return ((*((sal_uInt8*)pLong + 0) << 24) | |
| (*((sal_uInt8*)pLong + 1) << 16) | |
| (*((sal_uInt8*)pLong + 2) << 8) | |
| (*((sal_uInt8*)pLong + 3) << 0) ); |
| } |
| |
| // ------------------------------------------------------------------ |
| |
| sal_uInt64 ResMgr::GetUInt64( void* pDatum ) |
| { |
| return ((sal_uInt64(*((sal_uInt8*)pDatum + 0)) << 56) | |
| (sal_uInt64(*((sal_uInt8*)pDatum + 1)) << 48) | |
| (sal_uInt64(*((sal_uInt8*)pDatum + 2)) << 40) | |
| (sal_uInt64(*((sal_uInt8*)pDatum + 3)) << 32) | |
| (sal_uInt64(*((sal_uInt8*)pDatum + 4)) << 24) | |
| (sal_uInt64(*((sal_uInt8*)pDatum + 5)) << 16) | |
| (sal_uInt64(*((sal_uInt8*)pDatum + 6)) << 8) | |
| (sal_uInt64(*((sal_uInt8*)pDatum + 7)) << 0) ); |
| } |
| |
| // ----------------------------------------------------------------------- |
| sal_uInt32 ResMgr::GetStringWithoutHook( UniString& rStr, const sal_uInt8* pStr ) |
| { |
| sal_uInt32 nLen=0; |
| sal_uInt32 nRet = GetStringSize( pStr, nLen ); |
| UniString aString( (sal_Char*)pStr, RTL_TEXTENCODING_UTF8, |
| RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_MAPTOPRIVATE | |
| RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT | |
| RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT ); |
| rStr = aString; |
| return nRet; |
| } |
| |
| sal_uInt32 ResMgr::GetString( UniString& rStr, const sal_uInt8* pStr ) |
| { |
| UniString aString; |
| sal_uInt32 nRet = GetStringWithoutHook( aString, pStr ); |
| if ( pImplResHookProc ) |
| pImplResHookProc( aString ); |
| rStr = aString; |
| return nRet; |
| } |
| |
| sal_uInt32 ResMgr::GetByteString( rtl::OString& rStr, const sal_uInt8* pStr ) |
| { |
| sal_uInt32 nLen=0; |
| sal_uInt32 nRet = GetStringSize( pStr, nLen ); |
| rStr = rtl::OString( (const sal_Char*)pStr, nLen ); |
| return nRet; |
| } |
| |
| // ------------------------------------------------------------------ |
| |
| sal_uInt32 ResMgr::GetStringSize( const sal_uInt8* pStr, sal_uInt32& nLen ) |
| { |
| nLen = static_cast< sal_uInt32 >( strlen( (const char*)pStr ) ); |
| return GetStringSize( nLen ); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| sal_uInt32 ResMgr::GetRemainSize() |
| { |
| osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); |
| |
| if( pFallbackResMgr ) |
| return pFallbackResMgr->GetRemainSize(); |
| |
| const ImpRCStack& rTop = aStack[nCurStack]; |
| return (sal_uInt32)((long)(sal_uInt8 *)rTop.pResource + |
| rTop.pResource->GetLocalOff() - |
| (long)(sal_uInt8 *)rTop.pClassRes); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| void* ResMgr::Increment( sal_uInt32 nSize ) |
| { |
| osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); |
| |
| if( pFallbackResMgr ) |
| return pFallbackResMgr->Increment( nSize ); |
| |
| ImpRCStack& rStack = aStack[nCurStack]; |
| if( (rStack.Flags & RC_NOTFOUND) ) |
| return rStack.pClassRes; |
| |
| sal_uInt8* pClassRes = (sal_uInt8*)rStack.pClassRes + nSize; |
| |
| rStack.pClassRes = pClassRes; |
| |
| RSHEADER_TYPE* pRes = rStack.pResource; |
| |
| sal_uInt32 nLocalOff = pRes->GetLocalOff(); |
| if ( (pRes->GetGlobOff() == nLocalOff) && |
| (((char*)pRes + nLocalOff) == rStack.pClassRes) && |
| (rStack.Flags & RC_AUTORELEASE)) |
| { |
| PopContext( rStack.pResObj ); |
| } |
| |
| return pClassRes; |
| } |
| |
| ResMgr* ResMgr::CreateFallbackResMgr( const ResId& rId, const Resource* pResource ) |
| { |
| ResMgr *pFallback = NULL; |
| if( nCurStack > 0 ) |
| { |
| // get the next fallback level in resource file scope |
| InternalResMgr* pRes = ResMgrContainer::get().getNextFallback( pImpRes ); |
| if( pRes ) |
| { |
| // check that the fallback locale is not already in the chain of |
| // fallbacks - prevent fallback loops |
| ResMgr* pResMgr = this; |
| while( pResMgr && |
| ( pResMgr->pImpRes->aLocale.Language != pRes->aLocale.Language || |
| pResMgr->pImpRes->aLocale.Country != pRes->aLocale.Country || |
| pResMgr->pImpRes->aLocale.Variant != pRes->aLocale.Variant ) |
| ) |
| { |
| pResMgr = pResMgr->pOriginalResMgr; |
| } |
| if( pResMgr ) |
| { |
| // found a recursion, no fallback possible |
| ResMgrContainer::get().freeResMgr( pRes ); |
| return NULL; |
| } |
| OSL_TRACE( "trying fallback: %s\n", OUStringToOString( pRes->aFileName, osl_getThreadTextEncoding() ).getStr() ); |
| pFallback = new ResMgr( pRes ); |
| pFallback->pOriginalResMgr = this; |
| // try to recreate the resource stack |
| bool bHaveStack = true; |
| for( int i = 1; i < nCurStack; i++ ) |
| { |
| if( !aStack[i].pResource ) |
| { |
| bHaveStack = false; |
| break; |
| } |
| ResId aId( aStack[i].pResource->GetId(), *pFallbackResMgr ); |
| aId.SetRT( aStack[i].pResource->GetRT() ); |
| if( !pFallback->GetResource( aId ) ) |
| { |
| bHaveStack = false; |
| break; |
| } |
| } |
| if( bHaveStack ) |
| { |
| ResId aId( rId.GetId(), *pFallback ); |
| aId.SetRT( rId.GetRT() ); |
| if( !pFallback->GetResource( aId, pResource ) ) |
| bHaveStack = false; |
| else |
| pFallback->aStack[pFallback->nCurStack].Flags |= RC_FALLBACK_UP; |
| } |
| if( !bHaveStack ) |
| { |
| delete pFallback; |
| pFallback = NULL; |
| } |
| } |
| } |
| return pFallback; |
| } |
| |
| //--------------------------------------------------------------------------- |
| // |
| // method left here for SDK compatibility, |
| // used in "framework/source/services/substitutepathvars.cxx" |
| // |
| // phone numbers no longer in use for resource files |
| // |
| //--------------------------------------------------------------------------- |
| |
| const char* ResMgr::GetLang( LanguageType& nType, sal_uInt16 nPrio ) |
| { |
| if ( nType == LANGUAGE_SYSTEM || nType == LANGUAGE_DONTKNOW ) |
| nType = MsLangId::getSystemUILanguage(); |
| |
| if ( nPrio == 0 ) |
| { |
| switch ( nType ) |
| { |
| case LANGUAGE_DANISH: |
| return "45"; |
| |
| case LANGUAGE_DUTCH: |
| case LANGUAGE_DUTCH_BELGIAN: |
| return "31"; |
| |
| case LANGUAGE_ENGLISH: |
| case LANGUAGE_ENGLISH_UK: |
| case LANGUAGE_ENGLISH_EIRE: |
| case LANGUAGE_ENGLISH_SAFRICA: |
| case LANGUAGE_ENGLISH_JAMAICA: |
| case LANGUAGE_ENGLISH_BELIZE: |
| case LANGUAGE_ENGLISH_TRINIDAD: |
| case LANGUAGE_ENGLISH_ZIMBABWE: |
| case LANGUAGE_ENGLISH_PHILIPPINES: |
| return "44"; |
| |
| case LANGUAGE_ENGLISH_US: |
| case LANGUAGE_ENGLISH_CAN: |
| return "01"; |
| |
| case LANGUAGE_ENGLISH_AUS: |
| case LANGUAGE_ENGLISH_NZ: |
| return "61"; |
| case LANGUAGE_ESTONIAN: |
| return "77"; |
| |
| |
| case LANGUAGE_FINNISH: |
| return "35"; |
| |
| case LANGUAGE_FRENCH_CANADIAN: |
| return "02"; |
| |
| case LANGUAGE_FRENCH: |
| case LANGUAGE_FRENCH_BELGIAN: |
| case LANGUAGE_FRENCH_SWISS: |
| case LANGUAGE_FRENCH_LUXEMBOURG: |
| case LANGUAGE_FRENCH_MONACO: |
| return "33"; |
| |
| case LANGUAGE_GERMAN: |
| case LANGUAGE_GERMAN_SWISS: |
| case LANGUAGE_GERMAN_AUSTRIAN: |
| case LANGUAGE_GERMAN_LUXEMBOURG: |
| case LANGUAGE_GERMAN_LIECHTENSTEIN: |
| return "49"; |
| |
| case LANGUAGE_ITALIAN: |
| case LANGUAGE_ITALIAN_SWISS: |
| return "39"; |
| |
| case LANGUAGE_NORWEGIAN: |
| case LANGUAGE_NORWEGIAN_BOKMAL: |
| return "47"; |
| |
| case LANGUAGE_PORTUGUESE: |
| return "03"; |
| |
| case LANGUAGE_PORTUGUESE_BRAZILIAN: |
| return "55"; |
| |
| case LANGUAGE_SPANISH_DATED: |
| case LANGUAGE_SPANISH_MEXICAN: |
| case LANGUAGE_SPANISH_MODERN: |
| case LANGUAGE_SPANISH_GUATEMALA: |
| case LANGUAGE_SPANISH_COSTARICA: |
| case LANGUAGE_SPANISH_PANAMA: |
| case LANGUAGE_SPANISH_DOMINICAN_REPUBLIC: |
| case LANGUAGE_SPANISH_VENEZUELA: |
| case LANGUAGE_SPANISH_COLOMBIA: |
| case LANGUAGE_SPANISH_PERU: |
| case LANGUAGE_SPANISH_ARGENTINA: |
| case LANGUAGE_SPANISH_ECUADOR: |
| case LANGUAGE_SPANISH_CHILE: |
| case LANGUAGE_SPANISH_URUGUAY: |
| case LANGUAGE_SPANISH_PARAGUAY: |
| case LANGUAGE_SPANISH_BOLIVIA: |
| return "34"; |
| |
| case LANGUAGE_SWEDISH: |
| return "46"; |
| |
| case LANGUAGE_POLISH: |
| return "48"; |
| case LANGUAGE_CZECH: |
| return "42"; |
| case LANGUAGE_SLOVENIAN: |
| return "50"; |
| case LANGUAGE_HUNGARIAN: |
| return "36"; |
| case LANGUAGE_RUSSIAN: |
| return "07"; |
| case LANGUAGE_SLOVAK: |
| return "43"; |
| case LANGUAGE_GREEK: |
| return "30"; |
| case LANGUAGE_TURKISH: |
| return "90"; |
| |
| case LANGUAGE_CHINESE_SIMPLIFIED: |
| return "86"; |
| case LANGUAGE_CHINESE_TRADITIONAL: |
| return "88"; |
| case LANGUAGE_JAPANESE: |
| return "81"; |
| case LANGUAGE_KOREAN: |
| case LANGUAGE_KOREAN_JOHAB: |
| return "82"; |
| case LANGUAGE_THAI: |
| return "66"; |
| case LANGUAGE_HINDI: |
| return "91"; |
| |
| case LANGUAGE_ARABIC_PRIMARY_ONLY: |
| case LANGUAGE_ARABIC_IRAQ: |
| case LANGUAGE_ARABIC_EGYPT: |
| case LANGUAGE_ARABIC_LIBYA: |
| case LANGUAGE_ARABIC_ALGERIA: |
| case LANGUAGE_ARABIC_MOROCCO: |
| case LANGUAGE_ARABIC_TUNISIA: |
| case LANGUAGE_ARABIC_OMAN: |
| case LANGUAGE_ARABIC_YEMEN: |
| case LANGUAGE_ARABIC_SYRIA: |
| case LANGUAGE_ARABIC_JORDAN: |
| case LANGUAGE_ARABIC_LEBANON: |
| case LANGUAGE_ARABIC_KUWAIT: |
| case LANGUAGE_ARABIC_UAE: |
| case LANGUAGE_ARABIC_BAHRAIN: |
| case LANGUAGE_ARABIC_QATAR: |
| return "96"; |
| |
| case LANGUAGE_HEBREW: |
| return "97"; |
| |
| case LANGUAGE_CATALAN: |
| return "37"; |
| |
| default: |
| return "99"; |
| } |
| } |
| else if ( nPrio == 1 ) |
| { |
| switch ( nType ) |
| { |
| case LANGUAGE_FRENCH_CANADIAN: |
| return "33"; |
| |
| case LANGUAGE_PORTUGUESE_BRAZILIAN: |
| return "03"; |
| |
| default: |
| return NULL; |
| } |
| } |
| else if ( nPrio == 2 ) |
| return "01"; |
| else if ( nPrio == 3 ) |
| return "44"; |
| else if ( nPrio == 4 ) |
| return "49"; |
| else |
| return "99"; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| ResMgr* ResMgr::CreateResMgr( const sal_Char* pPrefixName, |
| com::sun::star::lang::Locale aLocale ) |
| { |
| osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); |
| |
| OUString aPrefix( pPrefixName, strlen( pPrefixName ), osl_getThreadTextEncoding() ); |
| |
| if( ! aLocale.Language.getLength() ) |
| aLocale = ResMgrContainer::get().getDefLocale(); |
| |
| InternalResMgr* pImp = ResMgrContainer::get().getResMgr( aPrefix, aLocale ); |
| return pImp ? new ResMgr( pImp ) : NULL; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| ResMgr* ResMgr::SearchCreateResMgr( |
| const sal_Char* pPrefixName, |
| com::sun::star::lang::Locale& rLocale ) |
| { |
| osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); |
| |
| OUString aPrefix( pPrefixName, strlen( pPrefixName ), osl_getThreadTextEncoding() ); |
| |
| if( ! rLocale.Language.getLength() ) |
| rLocale = ResMgrContainer::get().getDefLocale(); |
| |
| InternalResMgr* pImp = ResMgrContainer::get().getResMgr( aPrefix, rLocale ); |
| return pImp ? new ResMgr( pImp ) : NULL; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| sal_Int16 ResMgr::ReadShort() |
| { |
| osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); |
| |
| if( pFallbackResMgr ) |
| return pFallbackResMgr->ReadShort(); |
| |
| sal_Int16 n = GetShort( GetClass() ); |
| Increment( sizeof( sal_Int16 ) ); |
| return n; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| sal_Int32 ResMgr::ReadLong() |
| { |
| osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); |
| |
| if( pFallbackResMgr ) |
| return pFallbackResMgr->ReadLong(); |
| |
| sal_Int32 n = GetLong( GetClass() ); |
| Increment( sizeof( sal_Int32 ) ); |
| return n; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| UniString ResMgr::ReadStringWithoutHook() |
| { |
| osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); |
| |
| if( pFallbackResMgr ) |
| return pFallbackResMgr->ReadStringWithoutHook(); |
| |
| UniString aRet; |
| |
| const ImpRCStack& rTop = aStack[nCurStack]; |
| if( (rTop.Flags & RC_NOTFOUND) ) |
| { |
| #if OSL_DEBUG_LEVEL > 0 |
| aRet = OUString( RTL_CONSTASCII_USTRINGPARAM( "<resource not found>" ) ); |
| #endif |
| } |
| else |
| Increment( GetStringWithoutHook( aRet, (const sal_uInt8*)GetClass() ) ); |
| |
| return aRet; |
| } |
| |
| UniString ResMgr::ReadString() |
| { |
| UniString aRet = ReadStringWithoutHook(); |
| if ( pImplResHookProc ) |
| pImplResHookProc( aRet ); |
| return aRet; |
| } |
| |
| rtl::OString ResMgr::ReadByteString() |
| { |
| osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); |
| |
| if( pFallbackResMgr ) |
| return pFallbackResMgr->ReadByteString(); |
| |
| rtl::OString aRet; |
| |
| const ImpRCStack& rTop = aStack[nCurStack]; |
| if( (rTop.Flags & RC_NOTFOUND) ) |
| { |
| #if OSL_DEBUG_LEVEL > 0 |
| aRet = OString( "<resource not found>" ); |
| #endif |
| } |
| else |
| Increment( GetByteString( aRet, (const sal_uInt8*)GetClass() ) ); |
| |
| return aRet; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| rtl::OString ResMgr::GetAutoHelpId() |
| { |
| osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); |
| |
| if( pFallbackResMgr ) |
| return pFallbackResMgr->GetAutoHelpId(); |
| |
| OSL_ENSURE( nCurStack, "resource stack empty in Auto help id generation" ); |
| if( nCurStack < 1 || nCurStack > 2 ) |
| return rtl::OString(); |
| |
| // prepare HID, start with resource prefix |
| rtl::OStringBuffer aHID( 32 ); |
| aHID.append( rtl::OUStringToOString( pImpRes->aPrefix, RTL_TEXTENCODING_UTF8 ) ); |
| aHID.append( '.' ); |
| |
| // append type |
| const ImpRCStack *pRC = StackTop(); |
| OSL_ENSURE( pRC, "missing resource stack level" ); |
| |
| if ( nCurStack == 1 ) |
| { |
| // auto help ids for top level windows |
| switch( pRC->pResource->GetRT() ) { |
| case RSC_DOCKINGWINDOW: aHID.append( "DockingWindow" ); break; |
| case RSC_WORKWIN: aHID.append( "WorkWindow" ); break; |
| case RSC_MODELESSDIALOG: aHID.append( "ModelessDialog" ); break; |
| case RSC_FLOATINGWINDOW: aHID.append( "FloatingWindow" ); break; |
| case RSC_MODALDIALOG: aHID.append( "ModalDialog" ); break; |
| case RSC_TABPAGE: aHID.append( "TabPage" ); break; |
| default: return rtl::OString(); |
| } |
| } |
| else |
| { |
| // only controls with the following parents get auto help ids |
| const ImpRCStack *pRC1 = StackTop(1); |
| switch( pRC1->pResource->GetRT() ) { |
| case RSC_DOCKINGWINDOW: |
| case RSC_WORKWIN: |
| case RSC_MODELESSDIALOG: |
| case RSC_FLOATINGWINDOW: |
| case RSC_MODALDIALOG: |
| case RSC_TABPAGE: |
| // intentionally no breaks! |
| // auto help ids for controls |
| switch( pRC->pResource->GetRT() ) { |
| case RSC_TABCONTROL: aHID.append( "TabControl" ); break; |
| case RSC_RADIOBUTTON: aHID.append( "RadioButton" ); break; |
| case RSC_CHECKBOX: aHID.append( "CheckBox" ); break; |
| case RSC_TRISTATEBOX: aHID.append( "TriStateBox" ); break; |
| case RSC_EDIT: aHID.append( "Edit" ); break; |
| case RSC_MULTILINEEDIT: aHID.append( "MultiLineEdit" ); break; |
| case RSC_MULTILISTBOX: aHID.append( "MultiListBox" ); break; |
| case RSC_LISTBOX: aHID.append( "ListBox" ); break; |
| case RSC_COMBOBOX: aHID.append( "ComboBox" ); break; |
| case RSC_PUSHBUTTON: aHID.append( "PushButton" ); break; |
| case RSC_SPINFIELD: aHID.append( "SpinField" ); break; |
| case RSC_PATTERNFIELD: aHID.append( "PatternField" ); break; |
| case RSC_NUMERICFIELD: aHID.append( "NumericField" ); break; |
| case RSC_METRICFIELD: aHID.append( "MetricField" ); break; |
| case RSC_CURRENCYFIELD: aHID.append( "CurrencyField" ); break; |
| case RSC_DATEFIELD: aHID.append( "DateField" ); break; |
| case RSC_TIMEFIELD: aHID.append( "TimeField" ); break; |
| case RSC_IMAGERADIOBUTTON: aHID.append( "ImageRadioButton" ); break; |
| case RSC_NUMERICBOX: aHID.append( "NumericBox" ); break; |
| case RSC_METRICBOX: aHID.append( "MetricBox" ); break; |
| case RSC_CURRENCYBOX: aHID.append( "CurrencyBox" ); break; |
| case RSC_DATEBOX: aHID.append( "DateBox" ); break; |
| case RSC_TIMEBOX: aHID.append( "TimeBox" ); break; |
| case RSC_IMAGEBUTTON: aHID.append( "ImageButton" ); break; |
| case RSC_MENUBUTTON: aHID.append( "MenuButton" ); break; |
| case RSC_MOREBUTTON: aHID.append( "MoreButton" ); break; |
| default: |
| // no type, no auto HID |
| return rtl::OString(); |
| } |
| break; |
| default: |
| return rtl::OString(); |
| } |
| } |
| |
| // append resource id hierarchy |
| for( int nOff = nCurStack-1; nOff >= 0; nOff-- ) |
| { |
| aHID.append( '.' ); |
| pRC = StackTop( nOff ); |
| |
| OSL_ENSURE( pRC->pResource, "missing resource in resource stack level !" ); |
| if( pRC->pResource ) |
| aHID.append( sal_Int32( pRC->pResource->GetId() ) ); |
| } |
| |
| return aHID.makeStringAndClear(); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| void ResMgr::SetReadStringHook( ResHookProc pProc ) |
| { |
| osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); |
| pImplResHookProc = pProc; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| ResHookProc ResMgr::GetReadStringHook() |
| { |
| return pImplResHookProc; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| void ResMgr::SetDefaultLocale( const com::sun::star::lang::Locale& rLocale ) |
| { |
| osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); |
| ResMgrContainer::get().setDefLocale( rLocale ); |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| const OUString& ResMgr::GetFileName() const |
| { |
| return pImpRes->aFileName; |
| } |
| |
| // ======================================================================= |
| |
| SimpleResMgr::SimpleResMgr( const sal_Char* pPrefixName, |
| const ::com::sun::star::lang::Locale& rLocale ) |
| { |
| OUString aPrefix( pPrefixName, strlen( pPrefixName ), osl_getThreadTextEncoding() ); |
| com::sun::star::lang::Locale aLocale( rLocale ); |
| |
| osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); |
| if( ! aLocale.Language.getLength() ) |
| aLocale = ResMgrContainer::get().getDefLocale(); |
| |
| m_pResImpl = ResMgrContainer::get().getResMgr( aPrefix, aLocale, true ); |
| DBG_ASSERT( m_pResImpl, "SimpleResMgr::SimpleResMgr : have no impl class !" ); |
| } |
| |
| // ----------------------------------------------------------------------- |
| SimpleResMgr::SimpleResMgr( const ::rtl::OUString& _rPrefixName, ::com::sun::star::lang::Locale& _inout_Locale ) |
| { |
| osl::Guard<osl::Mutex> aGuard( getResMgrMutex() ); |
| m_pResImpl = ResMgrContainer::get().getResMgr( _rPrefixName, _inout_Locale, true ); |
| } |
| |
| // ----------------------------------------------------------------------- |
| SimpleResMgr::~SimpleResMgr() |
| { |
| delete m_pResImpl; |
| } |
| |
| // ----------------------------------------------------------------------- |
| SimpleResMgr* SimpleResMgr::Create( const sal_Char* pPrefixName, com::sun::star::lang::Locale aLocale ) |
| { |
| return new SimpleResMgr( pPrefixName, aLocale ); |
| } |
| |
| // ----------------------------------------------------------------------- |
| bool SimpleResMgr::IsAvailable( RESOURCE_TYPE _resourceType, sal_uInt32 _resourceId ) |
| { |
| vos::OGuard aGuard(m_aAccessSafety); |
| |
| if ( ( RSC_STRING != _resourceType ) && ( RSC_RESOURCE != _resourceType ) ) |
| return false; |
| |
| DBG_ASSERT( m_pResImpl, "SimpleResMgr::IsAvailable: have no impl class !" ); |
| return m_pResImpl->IsGlobalAvailable( _resourceType, _resourceId ); |
| } |
| |
| // ----------------------------------------------------------------------- |
| UniString SimpleResMgr::ReadString( sal_uInt32 nId ) |
| { |
| vos::OGuard aGuard(m_aAccessSafety); |
| |
| DBG_ASSERT( m_pResImpl, "SimpleResMgr::ReadString : have no impl class !" ); |
| // perhaps constructed with an invalid filename ? |
| |
| UniString sReturn; |
| if ( !m_pResImpl ) |
| return sReturn; |
| |
| void* pResHandle = NULL; |
| InternalResMgr* pFallback = m_pResImpl; |
| RSHEADER_TYPE* pResHeader = (RSHEADER_TYPE*)m_pResImpl->LoadGlobalRes( RSC_STRING, nId, &pResHandle ); |
| if ( !pResHeader ) |
| { |
| osl::Guard<osl::Mutex> aGuard2( getResMgrMutex() ); |
| |
| // try fallback |
| while( ! pResHandle && pFallback ) |
| { |
| InternalResMgr* pOldFallback = pFallback; |
| pFallback = ResMgrContainer::get().getNextFallback( pFallback ); |
| if( pOldFallback != m_pResImpl ) |
| ResMgrContainer::get().freeResMgr( pOldFallback ); |
| if( pFallback ) |
| { |
| // handle possible recursion |
| if( pFallback->aLocale.Language != m_pResImpl->aLocale.Language || |
| pFallback->aLocale.Country != m_pResImpl->aLocale.Country || |
| pFallback->aLocale.Variant != m_pResImpl->aLocale.Variant ) |
| { |
| pResHeader = (RSHEADER_TYPE*)pFallback->LoadGlobalRes( RSC_STRING, nId, &pResHandle ); |
| } |
| else |
| { |
| ResMgrContainer::get().freeResMgr( pFallback ); |
| pFallback = NULL; |
| } |
| } |
| } |
| if( ! pResHandle ) |
| // no such resource |
| return sReturn; |
| } |
| |
| // sal_uIntPtr nLen = pResHeader->GetLocalOff() - sizeof(RSHEADER_TYPE); |
| ResMgr::GetString( sReturn, (const sal_uInt8*)(pResHeader+1) ); |
| |
| // not neccessary with te current implementation which holds the string table permanently, but to be sure .... |
| // note: pFallback cannot be NULL here and is either the fallback or m_pResImpl |
| pFallback->FreeGlobalRes( pResHeader, pResHandle ); |
| if( m_pResImpl != pFallback ) |
| { |
| osl::Guard<osl::Mutex> aGuard2( getResMgrMutex() ); |
| |
| ResMgrContainer::get().freeResMgr( pFallback ); |
| } |
| return sReturn; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| const ::com::sun::star::lang::Locale& SimpleResMgr::GetLocale() const |
| { |
| DBG_ASSERT( IsValid(), "SimpleResMgr::ReadBlob: invalid, this will crash!" ); |
| return m_pResImpl->aLocale; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| sal_uInt32 SimpleResMgr::ReadBlob( sal_uInt32 nId, void** pBuffer ) |
| { |
| vos::OGuard aGuard(m_aAccessSafety); |
| |
| DBG_ASSERT( m_pResImpl, "SimpleResMgr::ReadBlob : have no impl class !" ); |
| |
| // perhaps constructed with an invalid filename ? |
| DBG_ASSERT( pBuffer, "SimpleResMgr::ReadBlob : invalid argument !" ); |
| *pBuffer = NULL; |
| |
| void* pResHandle = NULL; |
| InternalResMgr* pFallback = m_pResImpl; |
| RSHEADER_TYPE* pResHeader = (RSHEADER_TYPE*)m_pResImpl->LoadGlobalRes( RSC_RESOURCE, nId, &pResHandle ); |
| DBG_ASSERT( pResHeader, "SimpleResMgr::ReadBlob : couldn't find the resource with the given id !" ); |
| |
| if ( !pResHeader ) |
| { |
| osl::Guard<osl::Mutex> aGuard2( getResMgrMutex() ); |
| |
| // try fallback |
| while( ! pResHandle && pFallback ) |
| { |
| InternalResMgr* pOldFallback = pFallback; |
| pFallback = ResMgrContainer::get().getNextFallback( pFallback ); |
| if( pOldFallback != m_pResImpl ) |
| ResMgrContainer::get().freeResMgr( pOldFallback ); |
| if( pFallback ) |
| { |
| // handle possible recursion |
| if( pFallback->aLocale.Language != m_pResImpl->aLocale.Language || |
| pFallback->aLocale.Country != m_pResImpl->aLocale.Country || |
| pFallback->aLocale.Variant != m_pResImpl->aLocale.Variant ) |
| { |
| pResHeader = (RSHEADER_TYPE*)pFallback->LoadGlobalRes( RSC_RESOURCE, nId, &pResHandle ); |
| } |
| else |
| { |
| ResMgrContainer::get().freeResMgr( pFallback ); |
| pFallback = NULL; |
| } |
| } |
| } |
| if( ! pResHandle ) |
| // no exception handling, this would require the locking of the solar mutex which isn't allowed within this class |
| return 0; |
| } |
| |
| DBG_ASSERT( pResHandle == NULL, "SimpleResMgr::ReadBlob : behaviour of LoadGlobalRes changed !" ); |
| // if pResHandle is not NULL the FreeBlob wouldn't have to delete the pointer given as pBuffer, but |
| // FreeBlob doesn't know that so it would probably crash .... |
| |
| sal_uInt32 nRemaining = pResHeader->GetLocalOff() - sizeof(RSHEADER_TYPE); |
| *pBuffer = (void*)(((sal_uInt8*)pResHeader) + sizeof(RSHEADER_TYPE)); |
| |
| // free an eventual fallback InternalResMgr |
| if( m_pResImpl != pFallback ) |
| { |
| osl::Guard<osl::Mutex> aGuard2( getResMgrMutex() ); |
| |
| ResMgrContainer::get().freeResMgr( pFallback ); |
| } |
| |
| return nRemaining; |
| } |
| |
| // ----------------------------------------------------------------------- |
| |
| void SimpleResMgr::FreeBlob( void* pBuffer ) |
| { |
| void* pCompleteBuffer = (void*)(((sal_uInt8*)pBuffer) - sizeof(RSHEADER_TYPE)); |
| rtl_freeMemory(pCompleteBuffer); |
| } |