diff options
Diffstat (limited to 'tools/source/rc/resmgr.cxx')
-rw-r--r-- | tools/source/rc/resmgr.cxx | 1364 |
1 files changed, 1364 insertions, 0 deletions
diff --git a/tools/source/rc/resmgr.cxx b/tools/source/rc/resmgr.cxx new file mode 100644 index 000000000000..610f884b9b2b --- /dev/null +++ b/tools/source/rc/resmgr.cxx @@ -0,0 +1,1364 @@ +/************************************************************************* + * + * $RCSfile: resmgr.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 17:03:06 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +#ifndef _VOS_SIGNAL_HXX_ +#include <vos/signal.hxx> +#endif + +#ifndef _NEW_HXX +#include <new.hxx> +#endif +#ifndef _DEBUG_HXX +#include <debug.hxx> +#endif +#ifndef _TABLE_HXX +#include <table.hxx> +#endif +#ifndef _FSYS_HXX +#include <fsys.hxx> +#endif +#ifndef _STREAM_HXX +#include <stream.hxx> +#endif +#ifndef _INTN_HXX +#include <intn.hxx> +#endif +#ifndef _TOOLS_RESMGR_HXX +#include <resmgr.hxx> +#endif +#ifndef _TOOLS_RC_HXX +#include <rc.hxx> +#endif +#ifndef _TOOLS_RCID_H +#include <rcid.h> +#endif + +#ifndef _TOOLS_SIMPLERESMGR_HXX_ +#include "simplerm.hxx" +#endif + +#pragma hdrstop + +// ======================================================================= + +extern ImplSVResourceData aResData; +inline ImplSVResourceData* GetResData() +{ + return &aResData; +} + +static List & GetResMgrList() +{ + ImplSVResourceData * pRD = GetResData(); + if ( !pRD->pInternalResMgrList ) + pRD->pInternalResMgrList = new List(); + return *pRD->pInternalResMgrList; +} + +struct ImpContent +{ + ULONG nTypeAndId; + ULONG nOffset; +}; + +#if defined( OS2 ) && defined( ICC ) +static int _Optlink Compare( const void * pFirst, const void * pSecond ) +#elif S390 +extern "C" { int Compare( const void * pFirst, const void * pSecond ) +#else +static int __LOADONCALLAPI Compare( const void * pFirst, const void * pSecond ) +#endif +{ + if( ((ImpContent *)pFirst)->nTypeAndId > ((ImpContent *)pSecond)->nTypeAndId ) + return( 1 ); + else if( ((ImpContent *)pFirst)->nTypeAndId < ((ImpContent *)pSecond)->nTypeAndId ) + return( -1 ); + else + return( 0 ); +} + +#ifdef S390 +} +#endif + +#if defined( OS2 ) && defined( ICC ) +static int _Optlink Search( const void * nTypeAndId, const void * pSecond ) +#elif S390 +extern "C" { int Search( const void * nTypeAndId, const void * pSecond ) +#else +static int __LOADONCALLAPI Search( const void * nTypeAndId, const void * pSecond ) +#endif +{ + if( (ULONG)nTypeAndId > (((ImpContent *)pSecond)->nTypeAndId) ) + return( 1 ); + else if( (ULONG)nTypeAndId < (((ImpContent *)pSecond)->nTypeAndId) ) + return( -1 ); + else + return( 0 ); +} + +#ifdef S390 +} +#endif + +// ======================================================================= + +SvStream * InternalResMgr::GetBitmapStream( USHORT nId ) +{ + // Anfang der Strings suchen + ImpContent * pFind = (ImpContent *) + bsearch( (void *)((ULONG(RT_SYS_BITMAP) << 16) | nId), pContent, nEntries, + sizeof( ImpContent ), Search ); + + if ( pFind ) + { + pStm->Seek( pFind->nOffset ); + return pStm; + } + return NULL; +} + +// ----------------------------------------------------------------------- + +void InternalResMgr::GetResMgrPath( InternalResMgr* pThis, + const UniString& rFileName, + const UniString* pAppFileName, + const UniString* pResourcePath ) +{ + UniString aResFile; + if ( rFileName.Len() ) + { + UniString aResPath; + if( pResourcePath ) + aResPath += *pResourcePath; + if ( pAppFileName ) + { + DirEntry aAppDir( *pAppFileName ); + aAppDir.CutName(); + UniString aAppPath = aAppDir.GetFull(); + DirEntry aResSubPath( UniString( RTL_CONSTASCII_USTRINGPARAM( "resource" ) ) ); + aAppDir += aResSubPath; + UniString aAppResPath = aAppDir.GetFull(); + + // Default resource path is bin\resource + if ( aResPath.Len() ) + aResPath += DirEntry::GetSearchDelimiter(); + aResPath += aAppResPath; + + // we a search also in the bin path + aResPath += DirEntry::GetSearchDelimiter(); + aResPath += aAppPath; + } + const sal_Char* pEnv = getenv( "STAR_RESOURCEPATH" ); + if( pEnv ) + { + if ( aResPath.Len() ) + aResPath += DirEntry::GetSearchDelimiter(); + aResPath.AppendAscii( pEnv ); + } + + DirEntry aFullName( rFileName ); + if ( aFullName.Find( aResPath ) ) + aResFile = aFullName.GetFull(); + else + aResFile = rFileName; + } + else if ( pAppFileName ) + { + // Default Resourcefile ist die Anwendung + aResFile = *pAppFileName; +#if defined( OS2 ) || defined( WIN ) || defined( WNT ) + aResFile.Erase( aResFile.Len() - 4 ); +#endif + aResFile.AppendAscii( ".res" ); + } + + if( aResFile.Len() ) + { + DirEntry aEntry = aResFile; + + FileStat aStat( aEntry ); + if( aStat.IsKind( FSYS_KIND_FILE ) ) + { + pThis->aFileName = aEntry.GetFull(); + pThis->aShortFileName = aEntry.GetName(); + } + } +} + +// ----------------------------------------------------------------------- + +InternalResMgr::InternalResMgr() + : pContent( NULL ) + , pStringBlock( NULL ) + , pStm( NULL ) + , bEqual2Content( TRUE ) + , nEntries( 0 ) + , pResUseDump( 0 ) +{ +} + +// ----------------------------------------------------------------------- + +InternalResMgr::~InternalResMgr() +{ + SvMemFree(pContent); + SvMemFree(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( aFileName, RTL_TEXTENCODING_UTF8 ) ); + aStm.WriteLine( aLine ); + + for( ULONG i = 0; i < pResUseDump->Count(); i++ ) + { + ULONG nKeyId = pResUseDump->GetObjectKey( i ); + aLine.Assign( "Type/Id: " ); + aLine.Append( ByteString::CreateFromInt32( (nKeyId >> 16) & 0xFFFF ) ); + aLine.Append( '/' ); + aLine.Append( ByteString::CreateFromInt32( nKeyId & 0xFFFF ) ); + aStm.WriteLine( aLine ); + } + } + } +#endif + + delete pResUseDump; +} + +// ----------------------------------------------------------------------- + +InternalResMgr* InternalResMgr::Create( const UniString& rName, + const UniString* pAppName, + const UniString* pResPath ) +{ + InternalResMgr* pThis = new InternalResMgr(); + + GetResMgrPath( pThis, rName, pAppName, pResPath ); + + if ( pThis->aFileName.Len() && pThis->Create() ) + return pThis; + + delete pThis; + return NULL; +} + +// ----------------------------------------------------------------------- + +BOOL InternalResMgr::Create() +{ + 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 ); + pContent = (ImpContent *)SvMemAlloc( lContLen ); + pStm->Read( pContent, lContLen ); + // Auf die Anzahl der ImpContent kürzen + nEntries = (UINT32)lContLen / sizeof( ImpContent ); + 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 Table(); + for( ULONG i = 0; i < nEntries; i++ ) + pResUseDump->Insert( pContent[i].nTypeAndId, NULL ); + } +#endif + // swap the content to the right endian + pContent[0].nTypeAndId = ResMgr::GetLong( &pContent[0].nTypeAndId ); + pContent[0].nOffset = ResMgr::GetLong( &pContent[0].nOffset ); + for( ULONG i = 0; i < nEntries -1; i++ ) + { + // swap the content to the right endian + pContent[i+1].nTypeAndId = ResMgr::GetLong( &pContent[i+1].nTypeAndId ); + pContent[i+1].nOffset = ResMgr::GetLong( &pContent[i+1].nOffset ); + if( pContent[i].nTypeAndId >= pContent[i +1].nTypeAndId ) + bSorted = FALSE; + if( (pContent[i].nTypeAndId & 0xFFFF0000) == (pContent[i +1].nTypeAndId & 0xFFFF0000) + && pContent[i].nOffset >= pContent[i +1].nOffset ) + bEqual2Content = FALSE; + } + } + DBG_ASSERT( bSorted, "content not sorted" ) + DBG_ASSERT( bEqual2Content, "resource structure wrong" ) + if( !bSorted ) + qsort( pContent, nEntries, sizeof( ImpContent ), Compare ); + + bDone = TRUE; + } + + return bDone; +} + +// ----------------------------------------------------------------------- + +InternalResMgr* InternalResMgr::GetInternalResMgr( const UniString& rFileName, + const UniString* pAppName, + const UniString* pResPath ) +{ + ImplSVResourceData* pSVInData = GetResData(); + + // Nur InternalResMgr's mit FileNamen stehen in der Liste + if ( rFileName.Len() ) + { + List& rMgrList = GetResMgrList(); + + InternalResMgr* pEle = (InternalResMgr*)rMgrList.First(); + while( pEle ) + { + if ( rFileName.EqualsIgnoreCaseAscii( pEle->aFileName ) || + rFileName.EqualsIgnoreCaseAscii( pEle->aShortFileName ) ) + { + pEle->AddRef(); + return pEle; + } + pEle = (InternalResMgr*)rMgrList.Next(); + } + +#ifdef DBG_UTIL + ByteString aTraceStr( "Search/Load-RESDLL:" ); + aTraceStr += ByteString( rFileName, RTL_TEXTENCODING_UTF8 ); + DBG_TRACE( aTraceStr.GetBuffer() ); +#endif + + pEle = Create( rFileName, pAppName, pResPath ); + + if ( pEle ) + { + pEle->AddRef(); + rMgrList.Insert( pEle ); + } + + return pEle; + } + + return NULL; +} + +// ----------------------------------------------------------------------- + +void InternalResMgr::FreeInternalResMgr( InternalResMgr* pFreeInternalResMgr ) +{ + // Nur InternalResMgr's mit FileNamen stehen in der Liste und werden vor dem + // Programmende freigegeben + if( pFreeInternalResMgr->aFileName.Len() ) + { + if( pFreeInternalResMgr->ReleaseRef() == 0 ) + GetResMgrList().Remove( pFreeInternalResMgr ); + } +} + +// ----------------------------------------------------------------------- + +BOOL InternalResMgr::IsGlobalAvailable( RESOURCE_TYPE nRT, USHORT nId ) const +{ + // Anfang der Strings suchen + ImpContent * pFind = (ImpContent *) + bsearch( (void *)((ULONG(nRT) << 16) | nId), pContent, nEntries, + sizeof( ImpContent ), Search ); + return pFind != NULL; +} + +// ----------------------------------------------------------------------- + +void* InternalResMgr::LoadGlobalRes( RESOURCE_TYPE nRT, USHORT nId, + void **pResHandle ) +{ +#ifdef DBG_UTIL + if( pResUseDump ) + pResUseDump->Remove( (ULONG(nRT) << 16) | nId ); +#endif + // Anfang der Strings suchen + ImpContent * pFind = (ImpContent *) + bsearch( (void *)((ULONG(nRT) << 16) | nId), pContent, nEntries, + sizeof( ImpContent ), Search ); + if( nRT == RSC_STRING && bEqual2Content && pFind ) + { + // String Optimierung + if( !pStringBlock ) + { + // Anfang der Strings suchen + ImpContent * pFirst = pFind; + ImpContent * pLast = pFirst; + while( pFirst > pContent && ((pFirst -1)->nTypeAndId >> 16) == RSC_STRING ) + pFirst--; + while( pLast < (pContent + nEntries) && (pLast->nTypeAndId >> 16) == 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*)SvMemAlloc( nSize ); + pStm->Seek( pFirst->nOffset ); + pStm->Read( pStringBlock, nSize ); + } + *pResHandle = pStringBlock; + return (BYTE*)pStringBlock + pFind->nOffset - nOffCorrection; + } + *pResHandle = 0; + if( pFind ) + { + RSHEADER_TYPE aHeader; + pStm->Seek( pFind->nOffset ); + pStm->Read( &aHeader, sizeof( RSHEADER_TYPE ) ); + void * pRes = new BYTE[ aHeader.GetGlobOff() ]; + memcpy( pRes, &aHeader, sizeof( RSHEADER_TYPE ) ); + pStm->Read( (BYTE*)pRes + sizeof( RSHEADER_TYPE ), + aHeader.GetGlobOff() - sizeof( RSHEADER_TYPE ) ); + return pRes; + } + //Resource holen + return NULL; +} + +// ----------------------------------------------------------------------- + +void InternalResMgr::FreeGlobalRes( void * pResHandle, void * pResource ) +{ + if ( !pResHandle ) + // REsource wurde extra allokiert + delete pResource; +} + +// ======================================================================= + +#ifdef DBG_UTIL + +UniString GetTypeRes_Impl( const ResId& rTypeId ) +{ + // Funktion verlassen, falls Resourcefehler in dieser Funktion + static bInUse = FALSE; + UniString aTypStr( rTypeId.GetId() ); + + if ( !bInUse ) + { + bInUse = TRUE; + + ResId aResId( RSCVERSION_ID ); + 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 + Resource::GetResManager()->Increment( sizeof( RSHEADER_TYPE ) ); + } + } + bInUse = FALSE; + } + + return aTypStr; +} + +// ----------------------------------------------------------------------- + +static void RscError_Impl( const sal_Char* pMessage, ResMgr* pResMgr, + RESOURCE_TYPE nRT, USHORT nId, + ImpRCStack* pResStack, short nStackTop ) +{ + // neuen ResourceMgr erzeugen + ResMgr* pNewResMgr = new ResMgr( pResMgr->GetFileName() ); + + ByteString aStr = ByteString( 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( nStackTop > 0 ) + { + aStr.Append( "Class: " ); + aStr.Append( ByteString( GetTypeRes_Impl( ResId( (pResStack + nStackTop)->pResource->GetRT(), pNewResMgr ) ), RTL_TEXTENCODING_UTF8 ) ); + aStr.Append( ", Id: " ); + aStr.Append( ByteString::CreateFromInt32( (long)(pResStack + nStackTop)->pResource->GetId() ) ); + nStackTop--; + } + + delete pNewResMgr; + + DBG_ERROR( aStr.GetBuffer() ); +} + +#endif + +// ======================================================================= + +static void RscException_Impl() +{ + switch ( NAMESPACE_VOS(OSignalHandler)::raise( OSL_SIGNAL_USER_RESOURCEFAILURE, (void*)"" ) ) + { + case NAMESPACE_VOS(OSignalHandler)::TAction_CallNextHandler: + abort(); + break; + + case NAMESPACE_VOS(OSignalHandler)::TAction_Ignore: + return; + break; + + case NAMESPACE_VOS(OSignalHandler)::TAction_AbortApplication: + abort(); + break; + + case NAMESPACE_VOS(OSignalHandler)::TAction_KillApplication: + exit(-1); + break; + } +} + +// ======================================================================= + +void ImpRCStack::Init( ResMgr* pMgr, const Resource* pObj, USHORT 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, + USHORT 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::DestroyAllResMgr() +{ + ImplSVResourceData* pSVInData = GetResData(); + + // Da auch von Abort gerufen werden kann, geben wir alle + // ResMgr's und alle InternalResMgr's hier frei + List* pMgrList = pSVInData->pInternalResMgrList; + if ( pMgrList ) + { + InternalResMgr* pEle = (InternalResMgr*)pMgrList->First(); + while ( pEle ) + { + DBG_WARNING1( "ResMgr's not destroyed: %s", + ByteString( pEle->aFileName, RTL_TEXTENCODING_UTF8 ).GetBuffer() ); + pEle->ReleaseReference(); + pEle = (InternalResMgr*)pMgrList->Next(); + } + delete pMgrList; + } +} + +// ----------------------------------------------------------------------- + +void ResMgr::Init( const UniString& rFileName ) +{ + if ( !pImpRes ) + { +#ifdef DBG_UTIL + ByteString aStr( "Resourcefile not found:\n" ); + aStr += ByteString( 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( pImpRes->aFileName, RTL_TEXTENCODING_UTF8 ); + DbgError( aStr.GetBuffer() ); + } + } +#endif + + nTopRes = 0; + aStack[0].Clear(); +} + +// ----------------------------------------------------------------------- + +ResMgr::ResMgr( const UniString& rFileName, + const UniString* pAppName, + const UniString* pResPath ) +{ + pImpRes = InternalResMgr::GetInternalResMgr( rFileName, pAppName, pResPath ); + Init( pImpRes ? (const UniString&)pImpRes->aFileName : rFileName ); +} + +// ----------------------------------------------------------------------- + +ResMgr::ResMgr( InternalResMgr * pImpMgr ) +{ + pImpRes = pImpMgr; + Init( pImpMgr->aFileName ); +} + +// ----------------------------------------------------------------------- + +ResMgr::~ResMgr() +{ + InternalResMgr::FreeInternalResMgr( pImpRes ); +} + +// ----------------------------------------------------------------------- + +#ifdef DBG_UTIL + +void ResMgr::TestStack( const Resource* pResObj ) +{ + if ( DbgIsResource() ) + { + for( short i = 1; i <= nTopRes; 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 +{ + BOOL bAvailable = FALSE; + RSHEADER_TYPE* pClassRes = rId.GetpResource(); + RESOURCE_TYPE nRT = rId.GetRT2(); + USHORT nId = rId.GetId(); + const ResMgr* pMgr = rId.GetResMgr(); + + if ( !pMgr ) + pMgr = this; + + if ( !pResObj || pResObj == pMgr->aStack[pMgr->nTopRes].pResObj ) + { + if ( !pClassRes ) + pClassRes = LocalResource( &pMgr->aStack[pMgr->nTopRes], nRT, nId ); + if ( pClassRes ) + { + if ( pClassRes->GetRT() == nRT ) + bAvailable = TRUE; + } + } + + // vieleicht globale Resource + if ( !pClassRes ) + bAvailable = pMgr->pImpRes->IsGlobalAvailable( nRT, nId ); + + return bAvailable; +} + +// ----------------------------------------------------------------------- + +inline ResMgr* GetActualResMgr() +{ + return GetResData()->pAppResMgr; +} + +// ----------------------------------------------------------------------- + +BOOL ResMgr::GetResource( const ResId& rId, const Resource* pResObj ) +{ + DBG_TESTSOLARMUTEX(); + + ResMgr* pMgr = rId.GetResMgr(); + if ( pMgr && (this != pMgr) ) + return pMgr->GetResource( rId, pResObj ); + + RSHEADER_TYPE* pClassRes = rId.GetpResource(); + RESOURCE_TYPE nRT = rId.GetRT2(); + USHORT nId = rId.GetId(); + + ResMgr* pLastMgr = GetActualResMgr(); + if ( pLastMgr != this ) + Resource::SetResManager( this ); + + nTopRes++; // Stackzeiger erhoehen + ImpRCStack* pTop = &aStack[nTopRes]; + pTop->Init( pLastMgr, 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, nTopRes -1 ); +#endif + RscException_Impl(); + nTopRes--; + return FALSE; + } + } + else + pTop->pClassRes = LocalResource( pTop -1, nRT, nId ); + + if ( pTop->pClassRes ) + // lokale Resource, nicht system Resource + pTop->pResource = (RSHEADER_TYPE *)pTop->pClassRes; + else + { + pTop->Flags |= RC_GLOBAL; + pTop->pClassRes = pImpRes->LoadGlobalRes( nRT, nId, &pTop->aResHandle ); + if ( pTop->pClassRes ) + pTop->pResource = (RSHEADER_TYPE *)pTop->pClassRes; + else + { +#ifdef DBG_UTIL + RscError_Impl( "Cannot load resource! ", + this, nRT, nId, aStack, nTopRes -1 ); +#endif + RscException_Impl(); + ImplSVResourceData * pRD = GetResData(); + nTopRes--; + return FALSE; + } + } + + return TRUE; +} + +// ----------------------------------------------------------------------- + +void * ResMgr::GetResourceSkipHeader( const ResId& rResId, ResMgr ** ppResMgr ) +{ + if ( rResId.GetResMgr() ) + *ppResMgr = rResId.GetResMgr(); + else + *ppResMgr = Resource::GetResManager(); + (*ppResMgr)->GetResource( rResId ); + (*ppResMgr)->Increment( sizeof( RSHEADER_TYPE ) ); + return (*ppResMgr)->GetClass(); +} + +// ----------------------------------------------------------------------- + +#ifdef DBG_UTIL +void ResMgr::PopContext( const Resource* pResObj ) +#else +void ResMgr::PopContext( const Resource* ) +#endif +{ +#ifdef DBG_UTIL + if ( DbgIsResource() ) + { + if ( (aStack[nTopRes].pResObj != pResObj) || !nTopRes ) + { + RscError_Impl( "Cannot free resource! ", this, + RSC_NOTYPE, 0, aStack, nTopRes ); + } + } +#endif + + if ( nTopRes ) + { + ImpRCStack* pTop = &aStack[nTopRes]; +#ifdef DBG_UTIL + if ( DbgIsResource() ) + { + 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, nTopRes -1 ); + } + } +#endif + + // Resource freigeben + if ( pTop->Flags & RC_GLOBAL ) + // kann auch Fremd-Ressource sein + pImpRes->FreeGlobalRes( pTop->aResHandle, pTop->pResource ); + if ( pTop->pResMgr != this ) + // wurde durch ResId gesetzt, automatisch zuruecksetzen + Resource::SetResManager( pTop->pResMgr ); + nTopRes--; + } +} + +// ----------------------------------------------------------------------- + +RSHEADER_TYPE* ResMgr::CreateBlock( const ResId& rId ) +{ + 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*)new BYTE[ 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 ) +{ +#ifdef __BIGENDIAN + return *(UINT16*)pShort; +#else + return SWAPSHORT( *(UINT16*)pShort ); +#endif +} + +// ------------------------------------------------------------------ + +INT32 ResMgr::GetLong( void * pLong ) +{ +#ifdef __BIGENDIAN + return (long)(((INT32)(*(UINT16*)pLong) << 16) | *(((UINT16*)pLong) + 1)); +#else + return ((INT32)(*(BYTE*)pLong) << 24) + | ((INT32)(*((BYTE*)pLong +1)) << 16) + | ((INT32)(*((BYTE*)pLong +2)) << 8) + | (INT32)(*((BYTE*)pLong +3)); +#endif +} + +// ----------------------------------------------------------------------- + +USHORT ResMgr::GetString( UniString& rStr, const BYTE* pStr ) +{ + 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 GetStringSize( pStr ); +} + +// ------------------------------------------------------------------ + +USHORT ResMgr::GetStringSize( const BYTE* pStr ) +{ + return GetStringSize( strlen( (const char*)pStr ) ); +} + +// ----------------------------------------------------------------------- + +USHORT ResMgr::GetRemainSize() +{ + return (USHORT)((long)(BYTE *)aStack[nTopRes].pResource + + aStack[nTopRes].pResource->GetLocalOff() - + (long)(BYTE *)aStack[nTopRes].pClassRes); +} + +// ----------------------------------------------------------------------- + +void* ResMgr::Increment( USHORT nSize ) +{ + BYTE* pClassRes = (BYTE*)aStack[nTopRes].pClassRes + nSize; + + aStack[nTopRes].pClassRes = pClassRes; + + RSHEADER_TYPE* pRes = aStack[nTopRes].pResource; + + if ( (pRes->GetGlobOff() == pRes->GetLocalOff()) && + (((char*)pRes + pRes->GetLocalOff()) == aStack[nTopRes].pClassRes) && + (aStack[nTopRes].Flags & RC_AUTORELEASE)) + { + PopContext( aStack[nTopRes].pResObj ); + } + + return pClassRes; +} + +// ----------------------------------------------------------------------- + +const char* ResMgr::GetLang( LanguageType& nType, USHORT nPrio ) +{ + static sal_Char const aDefEng[] = "44"; + static sal_Char const aDefUSEng[] = "01"; + static sal_Char const aDefGerman[] = "49"; + static sal_Char const aDefFrench[] = "33"; + static sal_Char const aDefPortuguese[] = "03"; + + if ( nType == LANGUAGE_SYSTEM || nType == LANGUAGE_DONTKNOW ) + nType = ::GetSystemLanguage(); + + 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 aDefEng; + + case LANGUAGE_ENGLISH_US: + case LANGUAGE_ENGLISH_CAN: + return aDefUSEng; + + case LANGUAGE_ENGLISH_AUS: + case LANGUAGE_ENGLISH_NZ: + return "61"; + + case LANGUAGE_FINNISH: + return "05"; + + 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 aDefFrench; + + case LANGUAGE_GERMAN: + case LANGUAGE_GERMAN_SWISS: + case LANGUAGE_GERMAN_AUSTRIAN: + case LANGUAGE_GERMAN_LUXEMBOURG: + case LANGUAGE_GERMAN_LIECHTENSTEIN: + return aDefGerman; + + case LANGUAGE_ITALIAN: + case LANGUAGE_ITALIAN_SWISS: + return "39"; + + case LANGUAGE_NORWEGIAN: + case LANGUAGE_NORWEGIAN_BOKMAL: + return "47"; + + case LANGUAGE_PORTUGUESE: + return aDefPortuguese; + + case LANGUAGE_PORTUGUESE_BRAZILIAN: + return "55"; + + case LANGUAGE_SPANISH: + 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_HUNGARIAN: + return "36"; + case LANGUAGE_RUSSIAN: + return "07"; + case LANGUAGE_SLOVAK: + return "04"; + 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_ARABIC: + 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"; + + default: + return aDefUSEng; + } + } + else if ( nPrio == 1 ) + { + switch ( nType ) + { + case LANGUAGE_FRENCH_CANADIAN: + return aDefFrench; + + case LANGUAGE_PORTUGUESE_BRAZILIAN: + return aDefPortuguese; + + default: + return NULL; + } + } + else if ( nPrio == 2 ) + return aDefUSEng; + else if ( nPrio == 3 ) + return aDefEng; + else + return aDefGerman; +} + +// ----------------------------------------------------------------------- + +ResMgr* ResMgr::CreateResMgr( const sal_Char* pPrefixName, + LanguageType nType, + const UniString* pAppName, + const UniString* pResPath ) +{ + // Suchreihenfolge festlegen + const sal_Char* pLang[5]; + + // Resourcefile suchen + UniString aName; + InternalResMgr* pInternalResMgr = NULL; + for ( int i = 0; i < 5; i++ ) + { + pLang[i] = GetLang( nType, i ); + + if ( pLang[i] && (i == 0 || pLang[i] != pLang[0]) ) + { + aName.AssignAscii( pPrefixName ); + aName.AppendAscii( pLang[i] ); + aName.AppendAscii( ".res" ); + pInternalResMgr = InternalResMgr::GetInternalResMgr( aName, pAppName, pResPath ); + if ( pInternalResMgr ) + break; + } + } + + if ( pInternalResMgr ) + return new ResMgr( pInternalResMgr ); + + return NULL; +} + +// ----------------------------------------------------------------------- + +INT16 ResMgr::ReadShort() +{ + INT16 n = GetShort( GetClass() ); + Increment( sizeof( INT16 ) ); + return n; +} + +// ----------------------------------------------------------------------- + +INT32 ResMgr::ReadLong() +{ + INT32 n = GetLong( GetClass() ); + Increment( sizeof( INT32 ) ); + return n; +} + +// ----------------------------------------------------------------------- + +UniString ResMgr::ReadString() +{ + UniString aRet; + Increment( GetString( aRet, (const BYTE*)GetClass() ) ); + return aRet; +} + +// ======================================================================= + +SimpleResMgr::SimpleResMgr( const sal_Char* pPrefixName, + LanguageType nType, + const UniString* pAppName, + const UniString* pResPath ) +{ + // Suchreihenfolge festlegen + const sal_Char* pLang[5]; + + // Resourcefile suchen + UniString aName; + for ( int i = 0; i < 5; i++ ) + { + pLang[i] = ResMgr::GetLang( nType, i ); + + if ( pLang[i] && (i == 0 || pLang[i] != pLang[0]) ) + { + aName.AssignAscii( pPrefixName ); + aName.AppendAscii( pLang[i] ); + aName.AppendAscii( ".res" ); + m_pResImpl = InternalResMgr::Create( aName, pAppName, pResPath ); + if ( m_pResImpl ) + break; + } + } +} + +// ----------------------------------------------------------------------- + +SimpleResMgr::~SimpleResMgr() +{ + delete m_pResImpl; +} + +// ----------------------------------------------------------------------- + +UniString SimpleResMgr::ReadString( USHORT nId ) +{ + NAMESPACE_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; + RSHEADER_TYPE* pResHeader = (RSHEADER_TYPE*)m_pResImpl->LoadGlobalRes( RSC_STRING, nId, &pResHandle ); + if ( !pResHeader ) + // no such resource + return sReturn; + + USHORT 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 .... + m_pResImpl->FreeGlobalRes( pResHeader, pResHandle ); + return sReturn; +} + +// ----------------------------------------------------------------------- + +USHORT SimpleResMgr::ReadBlob( USHORT nId, void** pBuffer ) +{ + NAMESPACE_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; + 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 !" ); + + // no exception handling, this would require the locking of the solar mutex which isn't allowed within this class + if ( !pResHeader ) + 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 .... + + USHORT nRemaining = pResHeader->GetLocalOff() - sizeof(RSHEADER_TYPE); + *pBuffer = (void*)(((BYTE*)pResHeader) + sizeof(RSHEADER_TYPE)); + return nRemaining; +} + +// ----------------------------------------------------------------------- + +void SimpleResMgr::FreeBlob( void* pBuffer ) +{ + void* pCompleteBuffer = (void*)(((BYTE*)pBuffer) - sizeof(RSHEADER_TYPE)); + delete pCompleteBuffer; +} |