summaryrefslogtreecommitdiff
path: root/tools/source/rc/resmgr.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'tools/source/rc/resmgr.cxx')
-rw-r--r--tools/source/rc/resmgr.cxx2120
1 files changed, 2120 insertions, 0 deletions
diff --git a/tools/source/rc/resmgr.cxx b/tools/source/rc/resmgr.cxx
new file mode 100644
index 000000000000..2e6401f5a19f
--- /dev/null
+++ b/tools/source/rc/resmgr.cxx
@@ -0,0 +1,2120 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 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;
+ UINT32 nOffCorrection;
+ BYTE * pStringBlock;
+ SvStream * pStm;
+ BOOL bEqual2Content;
+ 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();
+ BOOL Create();
+
+ 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("$BRAND_BASE_DIR/program/resource"));
+ rtl::Bootstrap::expandMacros(uri);
+ aDirs.push_back(uri);
+ uri = rtl::OUString(
+ 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( 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;
+}
+
+// -----------------------------------------------------------------------
+
+
+BOOL InternalResMgr::Create()
+{
+ ResMgrContainer::get();
+ BOOL bDone = FALSE;
+
+ pStm = new SvFileStream( aFileName, (STREAM_READ | STREAM_SHARE_DENYWRITE | STREAM_NOCREATE) );
+ if( pStm->GetError() == 0 )
+ {
+ 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)
+ BYTE* pContentBuf = (BYTE*)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 = (UINT32)lContLen / 12;
+ bEqual2Content = TRUE; // Die Daten der Resourcen liegen
+ // genauso wie das Inhaltsverzeichnis
+ BOOL bSorted = 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 = FALSE;
+ if( (pContent[i].nTypeAndId & 0xFFFFFFFF00000000LL) == (pContent[j].nTypeAndId & 0xFFFFFFFF00000000LL)
+ && pContent[i].nOffset >= pContent[j].nOffset )
+ bEqual2Content = 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 = TRUE;
+ }
+
+ return bDone;
+}
+
+// -----------------------------------------------------------------------
+
+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;
+ UINT32 nSize;
+ --pLast;
+ pStm->Seek( pLast->nOffset );
+ RSHEADER_TYPE aHdr;
+ pStm->Read( &aHdr, sizeof( aHdr ) );
+ nSize = pLast->nOffset + aHdr.GetGlobOff() - nOffCorrection;
+ pStringBlock = (BYTE*)rtl_allocateMemory( nSize );
+ pStm->Seek( pFirst->nOffset );
+ pStm->Read( pStringBlock, nSize );
+ }
+ *pResHandle = pStringBlock;
+ return (BYTE*)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( (BYTE*)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 = FALSE;
+ UniString aTypStr( UniString::CreateFromInt32( rTypeId.GetId() ) );
+
+ if ( !bInUse )
+ {
+ bInUse = 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 = 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*)
+ ((BYTE*)pStack->pResource + pStack->pResource->GetLocalOff());
+ pEnd = (RSHEADER_TYPE*)
+ ((BYTE*)pStack->pResource + pStack->pResource->GetGlobOff());
+ while ( pTmp != pEnd )
+ {
+ if ( pTmp->GetRT() == nRTType && pTmp->GetId() == nId )
+ return pTmp;
+ pTmp = (RSHEADER_TYPE*)((BYTE*)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
+
+// -----------------------------------------------------------------------
+BOOL ResMgr::IsAvailable( const ResId& rId, const Resource* pResObj ) const
+{
+ osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
+
+ BOOL bAvailable = 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 = 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;
+}
+
+// -----------------------------------------------------------------------
+
+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 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 FALSE;
+ }
+ }
+ }
+
+ return 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 = (BYTE*)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;
+}
+
+// ------------------------------------------------------------------
+
+INT16 ResMgr::GetShort( void * pShort )
+{
+ return ((*((sal_uInt8*)pShort + 0) << 8) |
+ (*((sal_uInt8*)pShort + 1) << 0) );
+}
+
+// ------------------------------------------------------------------
+
+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 BYTE* 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 BYTE* 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 BYTE* 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 BYTE* 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)(BYTE *)rTop.pResource +
+ rTop.pResource->GetLocalOff() -
+ (long)(BYTE *)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;
+
+ BYTE* pClassRes = (BYTE*)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, USHORT 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;
+}
+
+// -----------------------------------------------------------------------
+
+INT16 ResMgr::ReadShort()
+{
+ osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
+
+ if( pFallbackResMgr )
+ return pFallbackResMgr->ReadShort();
+
+ INT16 n = GetShort( GetClass() );
+ Increment( sizeof( INT16 ) );
+ return n;
+}
+
+// -----------------------------------------------------------------------
+
+INT32 ResMgr::ReadLong()
+{
+ osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
+
+ if( pFallbackResMgr )
+ return pFallbackResMgr->ReadLong();
+
+ INT32 n = GetLong( GetClass() );
+ Increment( sizeof( 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 BYTE*)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 BYTE*)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;
+ }
+
+ // ULONG nLen = pResHeader->GetLocalOff() - sizeof(RSHEADER_TYPE);
+ ResMgr::GetString( sReturn, (const BYTE*)(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*)(((BYTE*)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*)(((BYTE*)pBuffer) - sizeof(RSHEADER_TYPE));
+ rtl_freeMemory(pCompleteBuffer);
+}