GPU-Calc: remove Alloc_Host_Ptr for clmem of NAN vector
[LibreOffice.git] / tools / source / rc / resmgr.cxx
blob9199ad17963b6e5a0bab675d3826635f265d199b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_folders.h>
22 #include "sal/config.h"
24 #include <cassert>
26 #include <string.h>
27 #include <stdio.h>
28 #include <stdlib.h>
30 #include <tools/debug.hxx>
31 #include <tools/stream.hxx>
32 #include <tools/resmgr.hxx>
33 #include <tools/rc.hxx>
34 #include <tools/rcid.h>
35 #include <osl/endian.h>
36 #include <osl/process.h>
37 #include <osl/thread.h>
38 #include <osl/file.hxx>
39 #include <osl/mutex.hxx>
40 #include <osl/signal.h>
41 #include <rtl/ustrbuf.hxx>
42 #include <rtl/strbuf.hxx>
43 #include <sal/log.hxx>
44 #include <rtl/instance.hxx>
45 #include <rtl/bootstrap.hxx>
46 #include <i18nlangtag/languagetag.hxx>
47 #include <i18nlangtag/mslangid.hxx>
48 #include <tools/simplerm.hxx>
50 #include <functional>
51 #include <algorithm>
52 #include <boost/unordered_map.hpp>
53 #include <list>
54 #include <set>
57 using namespace osl;
59 // for thread safety
60 static osl::Mutex* pResMgrMutex = NULL;
62 static osl::Mutex& getResMgrMutex()
64 if( !pResMgrMutex )
66 osl::Guard<osl::Mutex> aGuard( *osl::Mutex::getGlobalMutex() );
67 if( ! pResMgrMutex )
68 pResMgrMutex = new osl::Mutex();
70 return *pResMgrMutex;
73 struct ImpContent;
75 class InternalResMgr
77 friend class ResMgr;
78 friend class SimpleResMgr;
79 friend class ResMgrContainer;
81 ImpContent * pContent;
82 sal_uInt32 nOffCorrection;
83 sal_uInt8 * pStringBlock;
84 SvStream * pStm;
85 bool bEqual2Content;
86 sal_uInt32 nEntries;
87 OUString aFileName;
88 OUString aPrefix;
89 OUString aResName;
90 bool bSingular;
91 LanguageTag aLocale;
92 boost::unordered_map<sal_uInt64, int>* pResUseDump;
94 InternalResMgr( const OUString& rFileURL,
95 const OUString& aPrefix,
96 const OUString& aResName,
97 const LanguageTag& rLocale );
98 ~InternalResMgr();
99 bool Create();
101 bool IsGlobalAvailable( RESOURCE_TYPE nRT, sal_uInt32 nId ) const;
102 void * LoadGlobalRes( RESOURCE_TYPE nRT, sal_uInt32 nId,
103 void **pResHandle );
104 public:
105 static void FreeGlobalRes( void *, void * );
108 class ResMgrContainer
110 static ResMgrContainer* pOneInstance;
112 struct ContainerElement
114 InternalResMgr* pResMgr;
115 OUString aFileURL;
116 int nRefCount;
117 int nLoadCount;
119 ContainerElement() :
120 pResMgr( NULL ),
121 nRefCount( 0 ),
122 nLoadCount( 0 )
126 boost::unordered_map< OUString, ContainerElement, OUStringHash> m_aResFiles;
127 LanguageTag m_aDefLocale;
129 ResMgrContainer() : m_aDefLocale( LANGUAGE_SYSTEM) { init(); }
130 ~ResMgrContainer();
132 void init();
134 public:
135 static ResMgrContainer& get();
136 static void release();
138 InternalResMgr* getResMgr( const OUString& rPrefix,
139 LanguageTag& rLocale,
140 bool bForceNewInstance = false
142 InternalResMgr* getNextFallback( InternalResMgr* pResMgr );
144 void freeResMgr( InternalResMgr* pResMgr );
146 void setDefLocale( const LanguageTag& rLocale )
147 { m_aDefLocale = rLocale; }
148 const LanguageTag& getDefLocale() const
149 { return m_aDefLocale; }
152 ResMgrContainer* ResMgrContainer::pOneInstance = NULL;
154 ResMgrContainer& ResMgrContainer::get()
156 if( ! pOneInstance )
157 pOneInstance = new ResMgrContainer();
158 return *pOneInstance;
161 ResMgrContainer::~ResMgrContainer()
163 for( boost::unordered_map< OUString, ContainerElement, OUStringHash >::iterator it =
164 m_aResFiles.begin(); it != m_aResFiles.end(); ++it )
166 OSL_TRACE( "Resource file %s loaded %d times",
167 OUStringToOString( it->second.aFileURL, osl_getThreadTextEncoding() ).getStr(),
168 it->second.nLoadCount );
169 delete it->second.pResMgr;
173 void ResMgrContainer::release()
175 delete pOneInstance;
176 pOneInstance = NULL;
179 void ResMgrContainer::init()
181 assert( m_aResFiles.empty() );
183 // get resource path
184 OUString uri("$BRAND_BASE_DIR/" LIBO_SHARE_RESOURCE_FOLDER "/");
185 rtl::Bootstrap::expandMacros(uri); //TODO: detect failure
187 // collect all possible resource files
188 Directory aDir( uri );
189 if( aDir.open() == FileBase::E_None )
191 DirectoryItem aItem;
192 while( aDir.getNextItem( aItem ) == FileBase::E_None )
194 FileStatus aStatus(osl_FileStatus_Mask_FileName);
195 if( aItem.getFileStatus( aStatus ) == FileBase::E_None )
197 OUString aFileName = aStatus.getFileName();
198 if( ! aFileName.endsWithIgnoreAsciiCase( ".res" ) )
199 continue;
200 OUString aResName = aFileName.copy( 0, aFileName.getLength() - strlen(".res") );
201 if( aResName.isEmpty() )
202 continue;
203 assert( m_aResFiles.find( aResName ) == m_aResFiles.end() );
204 m_aResFiles[ aResName ].aFileURL = uri + aFileName;
205 SAL_INFO(
206 "tools.rc",
207 "ResMgrContainer: " << aResName << " -> "
208 << m_aResFiles[ aResName ].aFileURL );
212 else
213 SAL_WARN( "tools.rc", "opening dir " << uri << " failed" );
215 // set default language
216 LanguageType nLang = MsLangId::getSystemUILanguage();
217 m_aDefLocale.reset( nLang);
220 namespace
222 bool isAlreadyPureenUS(const LanguageTag &rLocale)
224 return ( rLocale.getLanguageType() == LANGUAGE_ENGLISH_US );
228 InternalResMgr* ResMgrContainer::getResMgr( const OUString& rPrefix,
229 LanguageTag& rLocale,
230 bool bForceNewInstance
233 LanguageTag aLocale( rLocale );
234 boost::unordered_map< OUString, ContainerElement, OUStringHash >::iterator it = m_aResFiles.end();
236 ::std::vector< OUString > aFallbacks( aLocale.getFallbackStrings( true));
237 if (!isAlreadyPureenUS( aLocale))
238 aFallbacks.push_back( "en-US"); // last resort if all fallbacks fail
240 for (::std::vector< OUString >::const_iterator fb( aFallbacks.begin()); fb != aFallbacks.end(); ++fb)
242 OUString aSearch( rPrefix + *fb );
243 it = m_aResFiles.find( aSearch );
244 if( it != m_aResFiles.end() )
246 // ensure InternalResMgr existance
247 if( ! it->second.pResMgr )
249 InternalResMgr* pImp =
250 new InternalResMgr( it->second.aFileURL, rPrefix, it->first, aLocale );
251 if( ! pImp->Create() )
253 delete pImp;
254 continue;
256 it->second.pResMgr = pImp;
258 break;
261 // try if there is anything with this prefix at all
262 if( it == m_aResFiles.end() )
264 aLocale.reset( LANGUAGE_SYSTEM);
265 it = m_aResFiles.find( rPrefix );
266 if( it == m_aResFiles.end() )
268 for( it = m_aResFiles.begin(); it != m_aResFiles.end(); ++it )
270 if( it->first.matchIgnoreAsciiCase( rPrefix ) )
272 // ensure InternalResMgr existance
273 if( ! it->second.pResMgr )
275 InternalResMgr* pImp =
276 new InternalResMgr( it->second.aFileURL,
277 rPrefix,
278 it->first,
279 aLocale );
280 if( ! pImp->Create() )
282 delete pImp;
283 continue;
285 it->second.pResMgr = pImp;
287 // try to guess locale
288 sal_Int32 nIndex = rPrefix.getLength();
289 if (nIndex < it->first.getLength())
290 aLocale.reset( it->first.copy( nIndex));
291 else
293 SAL_WARN( "tools.rc", "ResMgrContainer::getResMgr: it->first " <<
294 it->first << " shorter than prefix " << rPrefix);
296 break;
301 // give up
302 if( it == m_aResFiles.end() )
304 OUString sURL = rPrefix + rLocale.getBcp47() + ".res";
305 if ( m_aResFiles.find(sURL) == m_aResFiles.end() )
307 m_aResFiles[ sURL ].aFileURL = sURL;
308 return getResMgr(rPrefix,rLocale,bForceNewInstance);
309 } // if ( m_aResFiles.find(sURL) == m_aResFiles.end() )
310 return NULL;
313 rLocale = aLocale;
314 // at this point it->second.pResMgr must be filled either by creating a new one
315 // (then the refcount is still 0) or because we already had one
316 InternalResMgr* pImp = it->second.pResMgr;
318 if( it->second.nRefCount == 0 )
319 it->second.nLoadCount++;
321 // for SimpleResMgr
322 if( bForceNewInstance )
324 if( it->second.nRefCount == 0 )
326 // shortcut: the match algorithm already created the InternalResMgr
327 // take it instead of creating yet another one
328 it->second.pResMgr = NULL;
329 pImp->bSingular = true;
331 else
333 pImp = new InternalResMgr( it->second.aFileURL, rPrefix, it->first, aLocale );
334 pImp->bSingular = true;
335 if( !pImp->Create() )
337 delete pImp;
338 pImp = NULL;
340 else
341 it->second.nLoadCount++;
344 else
345 it->second.nRefCount++;
347 return pImp;
350 InternalResMgr* ResMgrContainer::getNextFallback( InternalResMgr* pMgr )
352 /* TODO-BCP47: this is nasty, but the previous code simply stripped a
353 * locale's variant and country in subsequent calls to end up with language
354 * only and then fallback to en-US if all failed, so this is at least
355 * equivalent if not better. Maybe this method could be changed to get
356 * passed / remember a fallback list and an index within to pick the next.
357 * */
359 ::std::vector< OUString > aFallbacks( pMgr->aLocale.getFallbackStrings( true));
360 // The first is the locale itself, use next fallback or en-US.
361 /* TODO: what happens if the chain is "en-US", "en" -> "en-US", ...
362 * This was already an issue with the previous code. */
363 LanguageTag aLocale( ((aFallbacks.size() > 1) ? aFallbacks[1] : OUString( "en-US")));
364 InternalResMgr* pNext = getResMgr( pMgr->aPrefix, aLocale, pMgr->bSingular );
365 // prevent recursion
366 if( pNext == pMgr || ( pNext && pNext->aResName.equals( pMgr->aResName ) ) )
368 if( pNext->bSingular )
369 delete pNext;
370 pNext = NULL;
372 return pNext;
375 void ResMgrContainer::freeResMgr( InternalResMgr* pResMgr )
377 if( pResMgr->bSingular )
378 delete pResMgr;
379 else
381 boost::unordered_map< OUString, ContainerElement, OUStringHash >::iterator it =
382 m_aResFiles.find( pResMgr->aResName );
383 if( it != m_aResFiles.end() )
385 DBG_ASSERT( it->second.nRefCount > 0, "InternalResMgr freed too often" );
386 if( it->second.nRefCount > 0 )
387 it->second.nRefCount--;
388 if( it->second.nRefCount == 0 )
390 delete it->second.pResMgr;
391 it->second.pResMgr = NULL;
397 void Resource::TestRes()
399 if( m_pResMgr )
400 m_pResMgr->TestStack( this );
403 struct ImpContent
405 sal_uInt64 nTypeAndId;
406 sal_uInt32 nOffset;
409 struct ImpContentLessCompare : public ::std::binary_function< ImpContent, ImpContent, bool>
411 inline bool operator() (const ImpContent& lhs, const ImpContent& rhs) const
413 return lhs.nTypeAndId < rhs.nTypeAndId;
417 static ResHookProc pImplResHookProc = 0;
419 InternalResMgr::InternalResMgr( const OUString& rFileURL,
420 const OUString& rPrefix,
421 const OUString& rResName,
422 const LanguageTag& rLocale )
423 : pContent( NULL )
424 , pStringBlock( NULL )
425 , pStm( NULL )
426 , bEqual2Content( true )
427 , nEntries( 0 )
428 , aFileName( rFileURL )
429 , aPrefix( rPrefix )
430 , aResName( rResName )
431 , bSingular( false )
432 , aLocale( rLocale )
433 , pResUseDump( 0 )
437 InternalResMgr::~InternalResMgr()
439 rtl_freeMemory(pContent);
440 rtl_freeMemory(pStringBlock);
441 delete pStm;
443 #ifdef DBG_UTIL
444 if( pResUseDump )
446 const sal_Char* pLogFile = getenv( "STAR_RESOURCE_LOGGING" );
447 if ( pLogFile )
449 SvFileStream aStm( OUString::createFromAscii( pLogFile ), STREAM_WRITE );
450 aStm.Seek( STREAM_SEEK_TO_END );
451 OStringBuffer aLine("FileName: ");
452 aLine.append(OUStringToOString(aFileName,
453 RTL_TEXTENCODING_UTF8));
454 aStm.WriteLine(aLine.makeStringAndClear());
456 for( boost::unordered_map<sal_uInt64, int>::const_iterator it = pResUseDump->begin();
457 it != pResUseDump->end(); ++it )
459 sal_uInt64 nKeyId = it->first;
460 aLine.append("Type/Id: ");
461 aLine.append(sal::static_int_cast< sal_Int32 >((nKeyId >> 32) & 0xFFFFFFFF));
462 aLine.append('/');
463 aLine.append(sal::static_int_cast< sal_Int32 >(nKeyId & 0xFFFFFFFF));
464 aStm.WriteLine(aLine.makeStringAndClear());
468 #endif
470 delete pResUseDump;
473 bool InternalResMgr::Create()
475 ResMgrContainer::get();
476 bool bDone = false;
478 pStm = new SvFileStream( aFileName, (STREAM_READ | STREAM_SHARE_DENYWRITE | STREAM_NOCREATE) );
479 if( pStm->GetError() == 0 )
481 sal_Int32 lContLen = 0;
483 pStm->Seek( STREAM_SEEK_TO_END );
485 if( ( pInternalResMgr->pHead = (RSHEADER_TYPE *)mmap( 0, nResourceFileSize,
486 PROT_READ, MAP_PRIVATE,
487 fRes, 0 ) ) != (RSHEADER_TYPE *)-1)
489 pStm->SeekRel( - (int)sizeof( lContLen ) );
490 pStm->Read( &lContLen, sizeof( lContLen ) );
491 // is bigendian, swab to the right endian
492 lContLen = ResMgr::GetLong( &lContLen );
493 pStm->SeekRel( -lContLen );
494 // allocate stored ImpContent data (12 bytes per unit)
495 sal_uInt8* pContentBuf = (sal_uInt8*)rtl_allocateMemory( lContLen );
496 pStm->Read( pContentBuf, lContLen );
497 // allocate ImpContent space (sizeof(ImpContent) per unit, not necessarily 12)
498 pContent = (ImpContent *)rtl_allocateMemory( sizeof(ImpContent)*lContLen/12 );
499 // Shorten to number of ImpContent
500 nEntries = (sal_uInt32)lContLen / 12;
501 bEqual2Content = true;
502 bool bSorted = true;
503 if( nEntries )
505 #ifdef DBG_UTIL
506 const sal_Char* pLogFile = getenv( "STAR_RESOURCE_LOGGING" );
507 if ( pLogFile )
509 pResUseDump = new boost::unordered_map<sal_uInt64, int>;
510 for( sal_uInt32 i = 0; i < nEntries; ++i )
511 (*pResUseDump)[pContent[i].nTypeAndId] = 1;
513 #endif
514 // swap the content to the right endian
515 pContent[0].nTypeAndId = ResMgr::GetUInt64( pContentBuf );
516 pContent[0].nOffset = ResMgr::GetLong( pContentBuf+8 );
517 sal_uInt32 nCount = nEntries - 1;
518 for( sal_uInt32 i = 0,j=1; i < nCount; ++i,++j )
520 // swap the content to the right endian
521 pContent[j].nTypeAndId = ResMgr::GetUInt64( pContentBuf + (12*j) );
522 pContent[j].nOffset = ResMgr::GetLong( pContentBuf + (12*j+8) );
523 if( pContent[i].nTypeAndId >= pContent[j].nTypeAndId )
524 bSorted = false;
525 if( (pContent[i].nTypeAndId & 0xFFFFFFFF00000000LL) == (pContent[j].nTypeAndId & 0xFFFFFFFF00000000LL)
526 && pContent[i].nOffset >= pContent[j].nOffset )
527 bEqual2Content = false;
530 rtl_freeMemory( pContentBuf );
531 OSL_ENSURE( bSorted, "content not sorted" );
532 OSL_ENSURE( bEqual2Content, "resource structure wrong" );
533 if( !bSorted )
534 ::std::sort(pContent,pContent+nEntries,ImpContentLessCompare());
535 // qsort( pContent, nEntries, sizeof( ImpContent ), Compare );
537 bDone = true;
540 return bDone;
544 bool InternalResMgr::IsGlobalAvailable( RESOURCE_TYPE nRT, sal_uInt32 nId ) const
546 // Anfang der Strings suchen
547 ImpContent aValue;
548 aValue.nTypeAndId = ((sal_uInt64(nRT) << 32) | nId);
549 ImpContent * pFind = ::std::lower_bound(pContent,
550 pContent + nEntries,
551 aValue,
552 ImpContentLessCompare());
553 return (pFind != (pContent + nEntries)) && (pFind->nTypeAndId == aValue.nTypeAndId);
557 void* InternalResMgr::LoadGlobalRes( RESOURCE_TYPE nRT, sal_uInt32 nId,
558 void **pResHandle )
560 #ifdef DBG_UTIL
561 if( pResUseDump )
562 pResUseDump->erase( (sal_uInt64(nRT) << 32) | nId );
563 #endif
564 // search beginning of string
565 ImpContent aValue;
566 aValue.nTypeAndId = ((sal_uInt64(nRT) << 32) | nId);
567 ImpContent* pEnd = (pContent + nEntries);
568 ImpContent* pFind = ::std::lower_bound( pContent,
569 pEnd,
570 aValue,
571 ImpContentLessCompare());
572 if( pFind && (pFind != pEnd) && (pFind->nTypeAndId == aValue.nTypeAndId) )
574 if( nRT == RSC_STRING && bEqual2Content )
576 // string optimization
577 if( !pStringBlock )
579 // search beginning of string
580 ImpContent * pFirst = pFind;
581 ImpContent * pLast = pFirst;
582 while( pFirst > pContent && ((pFirst -1)->nTypeAndId >> 32) == RSC_STRING )
583 --pFirst;
584 while( pLast < pEnd && (pLast->nTypeAndId >> 32) == RSC_STRING )
585 ++pLast;
586 nOffCorrection = pFirst->nOffset;
587 sal_uInt32 nSize;
588 --pLast;
589 pStm->Seek( pLast->nOffset );
590 RSHEADER_TYPE aHdr;
591 pStm->Read( &aHdr, sizeof( aHdr ) );
592 nSize = pLast->nOffset + aHdr.GetGlobOff() - nOffCorrection;
593 pStringBlock = (sal_uInt8*)rtl_allocateMemory( nSize );
594 pStm->Seek( pFirst->nOffset );
595 pStm->Read( pStringBlock, nSize );
597 *pResHandle = pStringBlock;
598 return (sal_uInt8*)pStringBlock + pFind->nOffset - nOffCorrection;
599 } // if( nRT == RSC_STRING && bEqual2Content )
600 else
602 *pResHandle = 0;
603 RSHEADER_TYPE aHeader;
604 pStm->Seek( pFind->nOffset );
605 pStm->Read( &aHeader, sizeof( RSHEADER_TYPE ) );
606 void * pRes = rtl_allocateMemory( aHeader.GetGlobOff() );
607 memcpy( pRes, &aHeader, sizeof( RSHEADER_TYPE ) );
608 pStm->Read( (sal_uInt8*)pRes + sizeof( RSHEADER_TYPE ),
609 aHeader.GetGlobOff() - sizeof( RSHEADER_TYPE ) );
610 return pRes;
612 } // if( pFind && (pFind != pEnd) && (pFind->nTypeAndId == nValue) )
613 *pResHandle = 0;
614 return NULL;
617 void InternalResMgr::FreeGlobalRes( void * pResHandle, void * pResource )
619 if ( !pResHandle )
620 // Free allocated resource
621 rtl_freeMemory(pResource);
624 #ifdef DBG_UTIL
626 OUString GetTypeRes_Impl( const ResId& rTypeId )
628 // Return on resource errors
629 static int bInUse = false;
630 OUString aTypStr(OUString::number(rTypeId.GetId()));
632 if ( !bInUse )
634 bInUse = true;
636 ResId aResId( sal_uInt32(RSCVERSION_ID), *rTypeId.GetResMgr() );
637 aResId.SetRT( RSC_VERSIONCONTROL );
639 if ( rTypeId.GetResMgr()->GetResource( aResId ) )
641 rTypeId.SetRT( RSC_STRING );
642 if ( rTypeId.GetResMgr()->IsAvailable( rTypeId ) )
644 aTypStr = rTypeId.toString();
645 // Set class pointer to the end
646 rTypeId.GetResMgr()->Increment( sizeof( RSHEADER_TYPE ) );
649 bInUse = false;
652 return aTypStr;
655 void ResMgr::RscError_Impl( const sal_Char* pMessage, ResMgr* pResMgr,
656 RESOURCE_TYPE nRT, sal_uInt32 nId,
657 std::vector< ImpRCStack >& rResStack, int nDepth )
659 // create a separate ResMgr with its own stack
660 // first get a second reference of the InternalResMgr
661 InternalResMgr* pImp =
662 ResMgrContainer::get().getResMgr( pResMgr->pImpRes->aPrefix,
663 pResMgr->pImpRes->aLocale,
664 true );
666 ResMgr* pNewResMgr = new ResMgr( pImp );
668 OStringBuffer aStr(OUStringToOString(pResMgr->GetFileName(),
669 RTL_TEXTENCODING_UTF8));
671 if (aStr.getLength())
672 aStr.append('\n');
674 aStr.append("Class: ");
675 aStr.append(OUStringToOString(GetTypeRes_Impl(ResId(nRT, *pNewResMgr)),
676 RTL_TEXTENCODING_UTF8));
677 aStr.append(", Id: ");
678 aStr.append(static_cast<sal_Int32>(nId));
679 aStr.append(". ");
680 aStr.append(pMessage);
682 aStr.append("\nResource Stack\n");
683 while( nDepth > 0 )
685 aStr.append("Class: ");
686 aStr.append(OUStringToOString(GetTypeRes_Impl(
687 ResId(rResStack[nDepth].pResource->GetRT(), *pNewResMgr)),
688 RTL_TEXTENCODING_UTF8));
689 aStr.append(", Id: ");
690 aStr.append(static_cast<sal_Int32>(
691 rResStack[nDepth].pResource->GetId()));
692 nDepth--;
695 // clean up
696 delete pNewResMgr;
698 OSL_FAIL(aStr.getStr());
701 #endif
703 static void RscException_Impl()
705 switch ( osl_raiseSignal( OSL_SIGNAL_USER_RESOURCEFAILURE, (void*)"" ) )
707 case osl_Signal_ActCallNextHdl:
708 abort();
710 case osl_Signal_ActIgnore:
711 return;
713 case osl_Signal_ActAbortApp:
714 abort();
716 default:
717 case osl_Signal_ActKillApp:
718 exit(-1);
722 void ImpRCStack::Init( ResMgr* pMgr, const Resource* pObj, sal_uInt32 Id )
724 pResource = NULL;
725 pClassRes = NULL;
726 Flags = RC_NOTYPE;
727 aResHandle = NULL;
728 pResObj = pObj;
729 nId = Id & ~RSC_DONTRELEASE; //TLX: Besser Init aendern
730 pResMgr = pMgr;
731 if ( !(Id & RSC_DONTRELEASE) )
732 Flags |= RC_AUTORELEASE;
735 void ImpRCStack::Clear()
737 pResource = NULL;
738 pClassRes = NULL;
739 Flags = RC_NOTYPE;
740 aResHandle = NULL;
741 pResObj = NULL;
742 nId = 0;
743 pResMgr = NULL;
746 static RSHEADER_TYPE* LocalResource( const ImpRCStack* pStack,
747 RESOURCE_TYPE nRTType,
748 sal_uInt32 nId )
750 // Returns position of the resource if found or NULL otherwise
751 RSHEADER_TYPE* pTmp; // Pointer to child resource
752 RSHEADER_TYPE* pEnd; // Pointer to the end of this resource
754 if ( pStack->pResource && pStack->pClassRes )
756 pTmp = (RSHEADER_TYPE*)
757 ((sal_uInt8*)pStack->pResource + pStack->pResource->GetLocalOff());
758 pEnd = (RSHEADER_TYPE*)
759 ((sal_uInt8*)pStack->pResource + pStack->pResource->GetGlobOff());
760 while ( pTmp != pEnd )
762 if ( pTmp->GetRT() == nRTType && pTmp->GetId() == nId )
763 return pTmp;
764 pTmp = (RSHEADER_TYPE*)((sal_uInt8*)pTmp + pTmp->GetGlobOff());
768 return NULL;
771 void* ResMgr::pEmptyBuffer = NULL;
773 void* ResMgr::getEmptyBuffer()
775 if( ! pEmptyBuffer )
776 pEmptyBuffer = rtl_allocateZeroMemory( 1024 );
777 return pEmptyBuffer;
780 void ResMgr::DestroyAllResMgr()
783 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
784 if( pEmptyBuffer )
786 rtl_freeMemory( pEmptyBuffer );
787 pEmptyBuffer = NULL;
789 ResMgrContainer::release();
791 delete pResMgrMutex;
792 pResMgrMutex = NULL;
795 void ResMgr::Init( const OUString& rFileName )
797 (void) rFileName; // avoid warning about unused parameter
798 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
800 if ( !pImpRes )
802 #ifdef DBG_UTIL
803 OStringBuffer aStr("Resourcefile not found:\n");
804 aStr.append(OUStringToOString(rFileName, RTL_TEXTENCODING_UTF8));
805 OSL_FAIL(aStr.getStr());
806 #endif
807 RscException_Impl();
809 #ifdef DBG_UTIL
810 else
812 void* aResHandle = 0; // Helper variable for resource handles
813 void* pVoid; // Pointer on the resource
815 pVoid = pImpRes->LoadGlobalRes( RSC_VERSIONCONTROL, RSCVERSION_ID,
816 &aResHandle );
817 if ( pVoid )
818 InternalResMgr::FreeGlobalRes( aResHandle, pVoid );
819 else
821 SAL_WARN("tools.rc", "Wrong version: " << pImpRes->aFileName);
824 #endif
825 nCurStack = -1;
826 aStack.clear();
827 pFallbackResMgr = pOriginalResMgr = NULL;
828 incStack();
831 ResMgr::ResMgr( InternalResMgr * pImpMgr )
833 pImpRes = pImpMgr;
834 Init( pImpMgr->aFileName );
837 ResMgr::~ResMgr()
839 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
841 ResMgrContainer::get().freeResMgr( pImpRes );
843 // clean up possible left rc stack frames
844 while( nCurStack > 0 )
846 if( ( aStack[nCurStack].Flags & (RC_GLOBAL | RC_NOTFOUND) ) == RC_GLOBAL )
847 InternalResMgr::FreeGlobalRes( aStack[nCurStack].aResHandle,
848 aStack[nCurStack].pResource );
849 nCurStack--;
853 void ResMgr::incStack()
855 nCurStack++;
856 if( nCurStack >= int(aStack.size()) )
857 aStack.push_back( ImpRCStack() );
858 aStack[nCurStack].Clear();
860 DBG_ASSERT( nCurStack < 32, "Resource stack unreasonably large" );
863 void ResMgr::decStack()
865 DBG_ASSERT( nCurStack > 0, "resource stack underrun !" );
866 if( (aStack[nCurStack].Flags & RC_FALLBACK_UP) )
868 nCurStack--;
869 // warning: this will delete *this, see below
870 pOriginalResMgr->decStack();
872 else
874 ImpRCStack& rTop = aStack[nCurStack];
875 if( (rTop.Flags & RC_FALLBACK_DOWN) )
877 #if OSL_DEBUG_LEVEL > 1
878 OSL_TRACE( "returning from fallback %s",
879 OUStringToOString(pFallbackResMgr->GetFileName(), osl_getThreadTextEncoding() ).getStr() );
880 #endif
881 delete pFallbackResMgr;
882 pFallbackResMgr = NULL;
884 nCurStack--;
888 #ifdef DBG_UTIL
890 void ResMgr::TestStack( const Resource* pResObj )
892 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
894 int upperLimit = nCurStack;
896 if ( upperLimit < 0 )
898 OSL_FAIL( "resource stack underrun!" );
899 upperLimit = aStack.size() - 1;
901 else if ( upperLimit >= static_cast<int>(aStack.size()) )
903 OSL_FAIL( "stack occupation index > allocated stack size" );
904 upperLimit = aStack.size() - 1;
907 if ( DbgIsResource() )
909 for( int i = 1; i <= upperLimit; ++i )
911 if ( aStack[i].pResObj == pResObj )
913 RscError_Impl( "Resource not freed! ", this,
914 aStack[i].pResource->GetRT(),
915 aStack[i].pResource->GetId(),
916 aStack, i-1 );
922 #else
924 void ResMgr::TestStack( const Resource* )
928 #endif
930 bool ResMgr::IsAvailable( const ResId& rId, const Resource* pResObj ) const
932 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
934 bool bAvailable = false;
935 RSHEADER_TYPE* pClassRes = rId.GetpResource();
936 RESOURCE_TYPE nRT = rId.GetRT2();
937 sal_uInt32 nId = rId.GetId();
938 const ResMgr* pMgr = rId.GetResMgr();
940 if ( !pMgr )
941 pMgr = this;
943 if( pMgr->pFallbackResMgr )
945 ResId aId( rId );
946 aId.SetResMgr( NULL );
947 return pMgr->pFallbackResMgr->IsAvailable( aId, pResObj );
950 if ( !pResObj || pResObj == pMgr->aStack[pMgr->nCurStack].pResObj )
952 if ( !pClassRes )
953 pClassRes = LocalResource( &pMgr->aStack[pMgr->nCurStack], nRT, nId );
954 if ( pClassRes )
956 if ( pClassRes->GetRT() == nRT )
957 bAvailable = true;
961 if ( !pClassRes )
962 bAvailable = pMgr->pImpRes->IsGlobalAvailable( nRT, nId );
964 return bAvailable;
967 void* ResMgr::GetClass()
969 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
971 if( pFallbackResMgr )
972 return pFallbackResMgr->GetClass();
974 return aStack[nCurStack].pClassRes;
977 bool ResMgr::GetResource( const ResId& rId, const Resource* pResObj )
979 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
981 if( pFallbackResMgr )
983 ResId aId( rId );
984 aId.SetResMgr( NULL );
985 return pFallbackResMgr->GetResource( aId, pResObj );
988 ResMgr* pMgr = rId.GetResMgr();
989 if ( pMgr && (this != pMgr) )
990 return pMgr->GetResource( rId, pResObj );
992 // normally Increment will pop the context; this is
993 // not possible in RC_NOTFOUND case, so pop a frame here
994 ImpRCStack* pTop = &aStack[nCurStack];
995 if( (pTop->Flags & RC_NOTFOUND) )
997 decStack();
1000 RSHEADER_TYPE* pClassRes = rId.GetpResource();
1001 RESOURCE_TYPE nRT = rId.GetRT2();
1002 sal_uInt32 nId = rId.GetId();
1004 incStack();
1005 pTop = &aStack[nCurStack];
1006 pTop->Init( pMgr, pResObj, nId |
1007 (rId.IsAutoRelease() ? 0 : RSC_DONTRELEASE) );
1009 if ( pClassRes )
1011 if ( pClassRes->GetRT() == nRT )
1012 pTop->pClassRes = pClassRes;
1013 else
1015 #ifdef DBG_UTIL
1016 RscError_Impl( "Different class and resource type!",
1017 this, nRT, nId, aStack, nCurStack-1 );
1018 #endif
1019 pTop->Flags |= RC_NOTFOUND;
1020 pTop->pClassRes = getEmptyBuffer();
1021 pTop->pResource = (RSHEADER_TYPE*)pTop->pClassRes;
1022 return false;
1025 else
1027 OSL_ENSURE( nCurStack > 0, "stack of 1 to shallow" );
1028 pTop->pClassRes = LocalResource( &aStack[nCurStack-1], nRT, nId );
1031 if ( pTop->pClassRes )
1032 // lokale Resource, nicht system Resource
1033 pTop->pResource = (RSHEADER_TYPE *)pTop->pClassRes;
1034 else
1036 pTop->pClassRes = pImpRes->LoadGlobalRes( nRT, nId, &pTop->aResHandle );
1037 if ( pTop->pClassRes )
1039 pTop->Flags |= RC_GLOBAL;
1040 pTop->pResource = (RSHEADER_TYPE *)pTop->pClassRes;
1042 else
1044 // try to get a fallback resource
1045 pFallbackResMgr = CreateFallbackResMgr( rId, pResObj );
1046 if( pFallbackResMgr )
1048 pTop->Flags |= RC_FALLBACK_DOWN;
1049 #ifdef DBG_UTIL
1050 OStringBuffer aMess("found resource ");
1051 aMess.append(static_cast<sal_Int32>(nId));
1052 aMess.append(" in fallback ");
1053 aMess.append(OUStringToOString(
1054 pFallbackResMgr->GetFileName(),
1055 osl_getThreadTextEncoding()));
1056 aMess.append('\n');
1057 RscError_Impl(aMess.getStr(),
1058 this, nRT, nId, aStack, nCurStack-1);
1059 #endif
1061 else
1063 #ifdef DBG_UTIL
1064 RscError_Impl( "Cannot load resource! ",
1065 this, nRT, nId, aStack, nCurStack-1 );
1066 #endif
1067 pTop->Flags |= RC_NOTFOUND;
1068 pTop->pClassRes = getEmptyBuffer();
1069 pTop->pResource = (RSHEADER_TYPE*)pTop->pClassRes;
1070 return false;
1075 return true;
1078 void * ResMgr::GetResourceSkipHeader( const ResId& rResId, ResMgr ** ppResMgr )
1080 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1082 DBG_ASSERT( rResId.GetResMgr(), "illegal ResId without ResMgr" );
1083 *ppResMgr = rResId.GetResMgr();
1084 if( *ppResMgr )
1086 (*ppResMgr)->GetResource( rResId );
1087 (*ppResMgr)->Increment( sizeof( RSHEADER_TYPE ) );
1088 return (*ppResMgr)->GetClass();
1090 return getEmptyBuffer();
1093 void ResMgr::PopContext( const Resource* pResObj )
1095 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1097 if( pFallbackResMgr )
1099 pFallbackResMgr->PopContext( pResObj );
1100 return;
1103 #ifdef DBG_UTIL
1104 if ( DbgIsResource() )
1106 if ( (aStack[nCurStack].pResObj != pResObj) || nCurStack == 0 )
1108 RscError_Impl( "Cannot free resource! ", this,
1109 RSC_NOTYPE, 0, aStack, nCurStack );
1112 #endif
1114 if ( nCurStack > 0 )
1116 ImpRCStack* pTop = &aStack[nCurStack];
1117 #ifdef DBG_UTIL
1118 if ( DbgIsResource() && !(pTop->Flags & RC_NOTFOUND) )
1120 void* pRes = (sal_uInt8*)pTop->pResource +
1121 pTop->pResource->GetLocalOff();
1123 if ( pTop->pClassRes != pRes )
1125 RscError_Impl( "Classpointer not at the end!",
1126 this, pTop->pResource->GetRT(),
1127 pTop->pResource->GetId(),
1128 aStack, nCurStack-1 );
1131 #endif
1133 // free resource
1134 if( (pTop->Flags & (RC_GLOBAL | RC_NOTFOUND)) == RC_GLOBAL )
1135 // free global resource if resource is foreign
1136 InternalResMgr::FreeGlobalRes( pTop->aResHandle, pTop->pResource );
1137 decStack();
1141 RSHEADER_TYPE* ResMgr::CreateBlock( const ResId& rId )
1143 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1145 if( pFallbackResMgr )
1147 ResId aId( rId );
1148 aId.SetResMgr( NULL );
1149 return pFallbackResMgr->CreateBlock( aId );
1152 RSHEADER_TYPE* pHeader = NULL;
1153 if ( GetResource( rId ) )
1155 // Pointer is at the beginning of the resource, thus
1156 // class pointer points to the header, and the remaining size
1157 // equals to total size of allocated memory
1158 pHeader = (RSHEADER_TYPE*)rtl_allocateMemory( GetRemainSize() );
1159 memcpy( pHeader, GetClass(), GetRemainSize() );
1160 Increment( pHeader->GetLocalOff() ); //ans Ende setzen
1161 if ( pHeader->GetLocalOff() != pHeader->GetGlobOff() )
1162 // Has sub-resources, thus release them as well
1163 PopContext();
1166 return pHeader;
1169 sal_Int16 ResMgr::GetShort( void * pShort )
1171 return ((*((sal_uInt8*)pShort + 0) << 8) |
1172 (*((sal_uInt8*)pShort + 1) << 0) );
1175 sal_Int32 ResMgr::GetLong( void * pLong )
1177 return ((*((sal_uInt8*)pLong + 0) << 24) |
1178 (*((sal_uInt8*)pLong + 1) << 16) |
1179 (*((sal_uInt8*)pLong + 2) << 8) |
1180 (*((sal_uInt8*)pLong + 3) << 0) );
1183 sal_uInt64 ResMgr::GetUInt64( void* pDatum )
1185 return ((sal_uInt64(*((sal_uInt8*)pDatum + 0)) << 56) |
1186 (sal_uInt64(*((sal_uInt8*)pDatum + 1)) << 48) |
1187 (sal_uInt64(*((sal_uInt8*)pDatum + 2)) << 40) |
1188 (sal_uInt64(*((sal_uInt8*)pDatum + 3)) << 32) |
1189 (sal_uInt64(*((sal_uInt8*)pDatum + 4)) << 24) |
1190 (sal_uInt64(*((sal_uInt8*)pDatum + 5)) << 16) |
1191 (sal_uInt64(*((sal_uInt8*)pDatum + 6)) << 8) |
1192 (sal_uInt64(*((sal_uInt8*)pDatum + 7)) << 0) );
1195 sal_uInt32 ResMgr::GetStringWithoutHook( OUString& rStr, const sal_uInt8* pStr )
1197 sal_uInt32 nLen=0;
1198 sal_uInt32 nRet = GetStringSize( pStr, nLen );
1199 const sal_Char* str = reinterpret_cast< const sal_Char* >( pStr );
1200 OUString aString( str, strlen( str ), RTL_TEXTENCODING_UTF8,
1201 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_MAPTOPRIVATE |
1202 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT |
1203 RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT );
1204 rStr = aString;
1205 return nRet;
1208 sal_uInt32 ResMgr::GetString( OUString& rStr, const sal_uInt8* pStr )
1210 OUString aString;
1211 sal_uInt32 nRet = GetStringWithoutHook( aString, pStr );
1212 if ( pImplResHookProc )
1213 aString = pImplResHookProc( aString );
1214 rStr = aString;
1215 return nRet;
1218 sal_uInt32 ResMgr::GetByteString( OString& rStr, const sal_uInt8* pStr )
1220 sal_uInt32 nLen=0;
1221 sal_uInt32 nRet = GetStringSize( pStr, nLen );
1222 rStr = OString( (const sal_Char*)pStr, nLen );
1223 return nRet;
1226 sal_uInt32 ResMgr::GetStringSize( const sal_uInt8* pStr, sal_uInt32& nLen )
1228 nLen = static_cast< sal_uInt32 >( strlen( (const char*)pStr ) );
1229 return GetStringSize( nLen );
1232 sal_uInt32 ResMgr::GetRemainSize()
1234 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1236 if( pFallbackResMgr )
1237 return pFallbackResMgr->GetRemainSize();
1239 const ImpRCStack& rTop = aStack[nCurStack];
1240 return (sal_uInt32)((sal_IntPtr)(sal_uInt8 *)rTop.pResource +
1241 rTop.pResource->GetLocalOff() -
1242 (sal_IntPtr)(sal_uInt8 *)rTop.pClassRes);
1245 void* ResMgr::Increment( sal_uInt32 nSize )
1247 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1249 if( pFallbackResMgr )
1250 return pFallbackResMgr->Increment( nSize );
1252 ImpRCStack& rStack = aStack[nCurStack];
1253 if( (rStack.Flags & RC_NOTFOUND) )
1254 return rStack.pClassRes;
1256 sal_uInt8* pClassRes = (sal_uInt8*)rStack.pClassRes + nSize;
1258 rStack.pClassRes = pClassRes;
1260 RSHEADER_TYPE* pRes = rStack.pResource;
1262 sal_uInt32 nLocalOff = pRes->GetLocalOff();
1263 if ( (pRes->GetGlobOff() == nLocalOff) &&
1264 (((char*)pRes + nLocalOff) == rStack.pClassRes) &&
1265 (rStack.Flags & RC_AUTORELEASE))
1267 PopContext( rStack.pResObj );
1270 return pClassRes;
1273 ResMgr* ResMgr::CreateFallbackResMgr( const ResId& rId, const Resource* pResource )
1275 ResMgr *pFallback = NULL;
1276 if( nCurStack > 0 )
1278 // get the next fallback level in resource file scope
1279 InternalResMgr* pRes = ResMgrContainer::get().getNextFallback( pImpRes );
1280 if( pRes )
1282 // check that the fallback locale is not already in the chain of
1283 // fallbacks - prevent fallback loops
1284 ResMgr* pResMgr = this;
1285 while( pResMgr && (pResMgr->pImpRes->aLocale != pRes->aLocale))
1287 pResMgr = pResMgr->pOriginalResMgr;
1289 if( pResMgr )
1291 // found a recursion, no fallback possible
1292 ResMgrContainer::get().freeResMgr( pRes );
1293 return NULL;
1295 OSL_TRACE( "trying fallback: %s", OUStringToOString( pRes->aFileName, osl_getThreadTextEncoding() ).getStr() );
1296 pFallback = new ResMgr( pRes );
1297 pFallback->pOriginalResMgr = this;
1298 // try to recreate the resource stack
1299 bool bHaveStack = true;
1300 for( int i = 1; i < nCurStack; i++ )
1302 if( !aStack[i].pResource )
1304 bHaveStack = false;
1305 break;
1307 ResId aId( aStack[i].pResource->GetId(), *pFallbackResMgr );
1308 aId.SetRT( aStack[i].pResource->GetRT() );
1309 if( !pFallback->GetResource( aId ) )
1311 bHaveStack = false;
1312 break;
1315 if( bHaveStack )
1317 ResId aId( rId.GetId(), *pFallback );
1318 aId.SetRT( rId.GetRT() );
1319 if( !pFallback->GetResource( aId, pResource ) )
1320 bHaveStack = false;
1321 else
1322 pFallback->aStack[pFallback->nCurStack].Flags |= RC_FALLBACK_UP;
1324 if( !bHaveStack )
1326 delete pFallback;
1327 pFallback = NULL;
1331 return pFallback;
1334 // method left here for SDK compatibility,
1335 // used in "framework/source/services/substitutepathvars.cxx"
1336 // phone numbers no longer in use for resource files
1338 const char* ResMgr::GetLang( LanguageType& nType, sal_uInt16 nPrio )
1340 if ( nType == LANGUAGE_SYSTEM || nType == LANGUAGE_DONTKNOW )
1341 nType = MsLangId::getSystemUILanguage();
1343 if ( nPrio == 0 )
1345 switch ( nType )
1347 case LANGUAGE_DANISH:
1348 return "45";
1350 case LANGUAGE_DUTCH:
1351 case LANGUAGE_DUTCH_BELGIAN:
1352 return "31";
1354 case LANGUAGE_ENGLISH:
1355 case LANGUAGE_ENGLISH_UK:
1356 case LANGUAGE_ENGLISH_EIRE:
1357 case LANGUAGE_ENGLISH_SAFRICA:
1358 case LANGUAGE_ENGLISH_JAMAICA:
1359 case LANGUAGE_ENGLISH_BELIZE:
1360 case LANGUAGE_ENGLISH_TRINIDAD:
1361 case LANGUAGE_ENGLISH_ZIMBABWE:
1362 case LANGUAGE_ENGLISH_PHILIPPINES:
1363 return "44";
1365 case LANGUAGE_ENGLISH_US:
1366 case LANGUAGE_ENGLISH_CAN:
1367 return "01";
1369 case LANGUAGE_ENGLISH_AUS:
1370 case LANGUAGE_ENGLISH_NZ:
1371 return "61";
1372 case LANGUAGE_ESTONIAN:
1373 return "77";
1376 case LANGUAGE_FINNISH:
1377 return "35";
1379 case LANGUAGE_FRENCH_CANADIAN:
1380 return "02";
1382 case LANGUAGE_FRENCH:
1383 case LANGUAGE_FRENCH_BELGIAN:
1384 case LANGUAGE_FRENCH_SWISS:
1385 case LANGUAGE_FRENCH_LUXEMBOURG:
1386 case LANGUAGE_FRENCH_MONACO:
1387 return "33";
1389 case LANGUAGE_GERMAN:
1390 case LANGUAGE_GERMAN_SWISS:
1391 case LANGUAGE_GERMAN_AUSTRIAN:
1392 case LANGUAGE_GERMAN_LUXEMBOURG:
1393 case LANGUAGE_GERMAN_LIECHTENSTEIN:
1394 return "49";
1396 case LANGUAGE_ITALIAN:
1397 case LANGUAGE_ITALIAN_SWISS:
1398 return "39";
1400 case LANGUAGE_NORWEGIAN:
1401 case LANGUAGE_NORWEGIAN_BOKMAL:
1402 return "47";
1404 case LANGUAGE_PORTUGUESE:
1405 return "03";
1407 case LANGUAGE_PORTUGUESE_BRAZILIAN:
1408 return "55";
1410 case LANGUAGE_SPANISH_DATED:
1411 case LANGUAGE_SPANISH_MEXICAN:
1412 case LANGUAGE_SPANISH_MODERN:
1413 case LANGUAGE_SPANISH_GUATEMALA:
1414 case LANGUAGE_SPANISH_COSTARICA:
1415 case LANGUAGE_SPANISH_PANAMA:
1416 case LANGUAGE_SPANISH_DOMINICAN_REPUBLIC:
1417 case LANGUAGE_SPANISH_VENEZUELA:
1418 case LANGUAGE_SPANISH_COLOMBIA:
1419 case LANGUAGE_SPANISH_PERU:
1420 case LANGUAGE_SPANISH_ARGENTINA:
1421 case LANGUAGE_SPANISH_ECUADOR:
1422 case LANGUAGE_SPANISH_CHILE:
1423 case LANGUAGE_SPANISH_URUGUAY:
1424 case LANGUAGE_SPANISH_PARAGUAY:
1425 case LANGUAGE_SPANISH_BOLIVIA:
1426 return "34";
1428 case LANGUAGE_SWEDISH:
1429 return "46";
1431 case LANGUAGE_POLISH:
1432 return "48";
1433 case LANGUAGE_CZECH:
1434 return "42";
1435 case LANGUAGE_SLOVENIAN:
1436 return "50";
1437 case LANGUAGE_HUNGARIAN:
1438 return "36";
1439 case LANGUAGE_RUSSIAN:
1440 return "07";
1441 case LANGUAGE_SLOVAK:
1442 return "43";
1443 case LANGUAGE_GREEK:
1444 return "30";
1445 case LANGUAGE_TURKISH:
1446 return "90";
1448 case LANGUAGE_CHINESE_SIMPLIFIED:
1449 return "86";
1450 case LANGUAGE_CHINESE_TRADITIONAL:
1451 return "88";
1452 case LANGUAGE_JAPANESE:
1453 return "81";
1454 case LANGUAGE_KOREAN:
1455 case LANGUAGE_KOREAN_JOHAB:
1456 return "82";
1457 case LANGUAGE_THAI:
1458 return "66";
1459 case LANGUAGE_HINDI:
1460 return "91";
1462 case LANGUAGE_ARABIC_PRIMARY_ONLY:
1463 case LANGUAGE_ARABIC_IRAQ:
1464 case LANGUAGE_ARABIC_EGYPT:
1465 case LANGUAGE_ARABIC_LIBYA:
1466 case LANGUAGE_ARABIC_ALGERIA:
1467 case LANGUAGE_ARABIC_MOROCCO:
1468 case LANGUAGE_ARABIC_TUNISIA:
1469 case LANGUAGE_ARABIC_OMAN:
1470 case LANGUAGE_ARABIC_YEMEN:
1471 case LANGUAGE_ARABIC_SYRIA:
1472 case LANGUAGE_ARABIC_JORDAN:
1473 case LANGUAGE_ARABIC_LEBANON:
1474 case LANGUAGE_ARABIC_KUWAIT:
1475 case LANGUAGE_ARABIC_UAE:
1476 case LANGUAGE_ARABIC_BAHRAIN:
1477 case LANGUAGE_ARABIC_QATAR:
1478 return "96";
1480 case LANGUAGE_HEBREW:
1481 return "97";
1483 case LANGUAGE_CATALAN:
1484 return "37";
1486 default:
1487 return "99";
1490 else if ( nPrio == 1 )
1492 switch ( nType )
1494 case LANGUAGE_FRENCH_CANADIAN:
1495 return "33";
1497 case LANGUAGE_PORTUGUESE_BRAZILIAN:
1498 return "03";
1500 default:
1501 return NULL;
1504 else if ( nPrio == 2 )
1505 return "01";
1506 else if ( nPrio == 3 )
1507 return "44";
1508 else if ( nPrio == 4 )
1509 return "49";
1510 else
1511 return "99";
1514 ResMgr* ResMgr::CreateResMgr( const sal_Char* pPrefixName,
1515 LanguageTag aLocale )
1517 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1519 OUString aPrefix( pPrefixName, strlen( pPrefixName ), osl_getThreadTextEncoding() );
1521 if( aLocale.isSystemLocale() )
1522 aLocale = ResMgrContainer::get().getDefLocale();
1524 InternalResMgr* pImp = ResMgrContainer::get().getResMgr( aPrefix, aLocale );
1525 return pImp ? new ResMgr( pImp ) : NULL;
1528 ResMgr* ResMgr::SearchCreateResMgr(
1529 const sal_Char* pPrefixName,
1530 LanguageTag& rLocale )
1532 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1534 OUString aPrefix( pPrefixName, strlen( pPrefixName ), osl_getThreadTextEncoding() );
1536 if( rLocale.isSystemLocale() )
1537 rLocale = ResMgrContainer::get().getDefLocale();
1539 InternalResMgr* pImp = ResMgrContainer::get().getResMgr( aPrefix, rLocale );
1540 return pImp ? new ResMgr( pImp ) : NULL;
1543 sal_Int16 ResMgr::ReadShort()
1545 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1547 if( pFallbackResMgr )
1548 return pFallbackResMgr->ReadShort();
1550 sal_Int16 n = GetShort( GetClass() );
1551 Increment( sizeof( sal_Int16 ) );
1552 return n;
1555 sal_Int32 ResMgr::ReadLong()
1557 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1559 if( pFallbackResMgr )
1560 return pFallbackResMgr->ReadLong();
1562 sal_Int32 n = GetLong( GetClass() );
1563 Increment( sizeof( sal_Int32 ) );
1564 return n;
1567 OUString ResMgr::ReadStringWithoutHook()
1569 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1571 if( pFallbackResMgr )
1572 return pFallbackResMgr->ReadStringWithoutHook();
1574 OUString aRet;
1576 const ImpRCStack& rTop = aStack[nCurStack];
1577 if( (rTop.Flags & RC_NOTFOUND) )
1579 #if OSL_DEBUG_LEVEL > 0
1580 aRet = "<resource not found>";
1581 #endif
1583 else
1584 Increment( GetStringWithoutHook( aRet, (const sal_uInt8*)GetClass() ) );
1586 return aRet;
1589 OUString ResMgr::ReadString()
1591 OUString aRet = ReadStringWithoutHook();
1592 if ( pImplResHookProc )
1593 aRet = pImplResHookProc( aRet );
1594 return aRet;
1597 OString ResMgr::ReadByteString()
1599 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1601 if( pFallbackResMgr )
1602 return pFallbackResMgr->ReadByteString();
1604 OString aRet;
1606 const ImpRCStack& rTop = aStack[nCurStack];
1607 if( (rTop.Flags & RC_NOTFOUND) )
1609 #if OSL_DEBUG_LEVEL > 0
1610 aRet = OString( "<resource not found>" );
1611 #endif
1613 else
1614 Increment( GetByteString( aRet, (const sal_uInt8*)GetClass() ) );
1616 return aRet;
1619 OString ResMgr::GetAutoHelpId()
1621 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1623 if( pFallbackResMgr )
1624 return pFallbackResMgr->GetAutoHelpId();
1626 OSL_ENSURE( nCurStack, "resource stack empty in Auto help id generation" );
1627 if( nCurStack < 1 || nCurStack > 2 )
1628 return OString();
1630 // prepare HID, start with resource prefix
1631 OStringBuffer aHID( 32 );
1632 aHID.append( OUStringToOString( pImpRes->aPrefix, RTL_TEXTENCODING_UTF8 ) );
1633 aHID.append( '.' );
1635 // append type
1636 const ImpRCStack *pRC = StackTop();
1637 OSL_ENSURE( pRC, "missing resource stack level" );
1639 if ( nCurStack == 1 )
1641 // auto help ids for top level windows
1642 switch( pRC->pResource->GetRT() ) {
1643 case RSC_DOCKINGWINDOW: aHID.append( "DockingWindow" ); break;
1644 case RSC_WORKWIN: aHID.append( "WorkWindow" ); break;
1645 case RSC_MODELESSDIALOG: aHID.append( "ModelessDialog" ); break;
1646 case RSC_FLOATINGWINDOW: aHID.append( "FloatingWindow" ); break;
1647 case RSC_MODALDIALOG: aHID.append( "ModalDialog" ); break;
1648 case RSC_TABPAGE: aHID.append( "TabPage" ); break;
1649 default: return OString();
1652 else
1654 // only controls with the following parents get auto help ids
1655 const ImpRCStack *pRC1 = StackTop(1);
1656 switch( pRC1->pResource->GetRT() ) {
1657 case RSC_DOCKINGWINDOW:
1658 case RSC_WORKWIN:
1659 case RSC_MODELESSDIALOG:
1660 case RSC_FLOATINGWINDOW:
1661 case RSC_MODALDIALOG:
1662 case RSC_TABPAGE:
1663 // intentionally no breaks!
1664 // auto help ids for controls
1665 switch( pRC->pResource->GetRT() ) {
1666 case RSC_TABCONTROL: aHID.append( "TabControl" ); break;
1667 case RSC_RADIOBUTTON: aHID.append( "RadioButton" ); break;
1668 case RSC_CHECKBOX: aHID.append( "CheckBox" ); break;
1669 case RSC_TRISTATEBOX: aHID.append( "TriStateBox" ); break;
1670 case RSC_EDIT: aHID.append( "Edit" ); break;
1671 case RSC_MULTILINEEDIT: aHID.append( "MultiLineEdit" ); break;
1672 case RSC_MULTILISTBOX: aHID.append( "MultiListBox" ); break;
1673 case RSC_LISTBOX: aHID.append( "ListBox" ); break;
1674 case RSC_COMBOBOX: aHID.append( "ComboBox" ); break;
1675 case RSC_PUSHBUTTON: aHID.append( "PushButton" ); break;
1676 case RSC_SPINFIELD: aHID.append( "SpinField" ); break;
1677 case RSC_PATTERNFIELD: aHID.append( "PatternField" ); break;
1678 case RSC_NUMERICFIELD: aHID.append( "NumericField" ); break;
1679 case RSC_METRICFIELD: aHID.append( "MetricField" ); break;
1680 case RSC_CURRENCYFIELD: aHID.append( "CurrencyField" ); break;
1681 case RSC_DATEFIELD: aHID.append( "DateField" ); break;
1682 case RSC_TIMEFIELD: aHID.append( "TimeField" ); break;
1683 case RSC_NUMERICBOX: aHID.append( "NumericBox" ); break;
1684 case RSC_METRICBOX: aHID.append( "MetricBox" ); break;
1685 case RSC_CURRENCYBOX: aHID.append( "CurrencyBox" ); break;
1686 case RSC_DATEBOX: aHID.append( "DateBox" ); break;
1687 case RSC_TIMEBOX: aHID.append( "TimeBox" ); break;
1688 case RSC_IMAGEBUTTON: aHID.append( "ImageButton" ); break;
1689 case RSC_MENUBUTTON: aHID.append( "MenuButton" ); break;
1690 case RSC_MOREBUTTON: aHID.append( "MoreButton" ); break;
1691 default:
1692 // no type, no auto HID
1693 return OString();
1695 break;
1696 default:
1697 return OString();
1701 // append resource id hierarchy
1702 for( int nOff = nCurStack-1; nOff >= 0; nOff-- )
1704 aHID.append( '.' );
1705 pRC = StackTop( nOff );
1707 OSL_ENSURE( pRC->pResource, "missing resource in resource stack level !" );
1708 if( pRC->pResource )
1709 aHID.append( sal_Int32( pRC->pResource->GetId() ) );
1712 return aHID.makeStringAndClear();
1715 void ResMgr::SetReadStringHook( ResHookProc pProc )
1717 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1718 pImplResHookProc = pProc;
1721 ResHookProc ResMgr::GetReadStringHook()
1723 return pImplResHookProc;
1726 void ResMgr::SetDefaultLocale( const LanguageTag& rLocale )
1728 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1729 ResMgrContainer::get().setDefLocale( rLocale );
1732 const OUString& ResMgr::GetFileName() const
1734 return pImpRes->aFileName;
1737 SimpleResMgr::SimpleResMgr( const sal_Char* pPrefixName,
1738 const LanguageTag& rLocale )
1740 OUString aPrefix( pPrefixName, strlen( pPrefixName ), osl_getThreadTextEncoding() );
1741 LanguageTag aLocale( rLocale );
1743 osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1744 if( aLocale.isSystemLocale() )
1745 aLocale = ResMgrContainer::get().getDefLocale();
1747 m_pResImpl = ResMgrContainer::get().getResMgr( aPrefix, aLocale, true );
1748 DBG_ASSERT( m_pResImpl, "SimpleResMgr::SimpleResMgr : have no impl class !" );
1751 SimpleResMgr::~SimpleResMgr()
1753 delete m_pResImpl;
1756 SimpleResMgr* SimpleResMgr::Create( const sal_Char* pPrefixName, LanguageTag aLocale )
1758 return new SimpleResMgr( pPrefixName, aLocale );
1761 bool SimpleResMgr::IsAvailable( RESOURCE_TYPE _resourceType, sal_uInt32 _resourceId )
1763 osl::MutexGuard aGuard(m_aAccessSafety);
1765 if ( ( RSC_STRING != _resourceType ) && ( RSC_RESOURCE != _resourceType ) )
1766 return false;
1768 DBG_ASSERT( m_pResImpl, "SimpleResMgr::IsAvailable: have no impl class !" );
1769 return m_pResImpl->IsGlobalAvailable( _resourceType, _resourceId );
1772 OUString SimpleResMgr::ReadString( sal_uInt32 nId )
1774 osl::MutexGuard aGuard(m_aAccessSafety);
1776 DBG_ASSERT( m_pResImpl, "SimpleResMgr::ReadString : have no impl class !" );
1777 // perhaps constructed with an invalid filename ?
1779 OUString sReturn;
1780 if ( !m_pResImpl )
1781 return sReturn;
1783 void* pResHandle = NULL;
1784 InternalResMgr* pFallback = m_pResImpl;
1785 RSHEADER_TYPE* pResHeader = (RSHEADER_TYPE*)m_pResImpl->LoadGlobalRes( RSC_STRING, nId, &pResHandle );
1786 if ( !pResHeader )
1788 osl::Guard<osl::Mutex> aGuard2( getResMgrMutex() );
1790 // try fallback
1791 while( ! pResHandle && pFallback )
1793 InternalResMgr* pOldFallback = pFallback;
1794 pFallback = ResMgrContainer::get().getNextFallback( pFallback );
1795 if( pOldFallback != m_pResImpl )
1796 ResMgrContainer::get().freeResMgr( pOldFallback );
1797 if( pFallback )
1799 // handle possible recursion
1800 if( pFallback->aLocale != m_pResImpl->aLocale )
1802 pResHeader = (RSHEADER_TYPE*)pFallback->LoadGlobalRes( RSC_STRING, nId, &pResHandle );
1804 else
1806 ResMgrContainer::get().freeResMgr( pFallback );
1807 pFallback = NULL;
1811 if( ! pResHandle )
1812 // no such resource
1813 return sReturn;
1816 // sal_uIntPtr nLen = pResHeader->GetLocalOff() - sizeof(RSHEADER_TYPE);
1817 ResMgr::GetString( sReturn, (const sal_uInt8*)(pResHeader+1) );
1819 // not necessary with te current implementation which holds the string table permanently, but to be sure ....
1820 // note: pFallback cannot be NULL here and is either the fallback or m_pResImpl
1821 InternalResMgr::FreeGlobalRes( pResHeader, pResHandle );
1822 if( m_pResImpl != pFallback )
1824 osl::Guard<osl::Mutex> aGuard2( getResMgrMutex() );
1826 ResMgrContainer::get().freeResMgr( pFallback );
1828 return sReturn;
1831 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */