xref: /aoo41x/main/tools/source/rc/resmgr.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_tools.hxx"
30 
31 #include <string.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <vos/signal.hxx>
35 #include <tools/debug.hxx>
36 #ifndef _TABLE_HXX
37 #include <tools/table.hxx>
38 #endif
39 #include <tools/stream.hxx>
40 #include <tools/resmgr.hxx>
41 #include <tools/rc.hxx>
42 #include <tools/rcid.h>
43 #include <osl/endian.h>
44 #include <osl/process.h>
45 #include <osl/thread.h>
46 #include <osl/file.hxx>
47 #include <osl/mutex.hxx>
48 #include <rtl/ustrbuf.hxx>
49 #include <rtl/strbuf.hxx>
50 #include <tools/urlobj.hxx>
51 #include <rtl/instance.hxx>
52 #include <rtl/bootstrap.hxx>
53 #include <i18npool/mslangid.hxx>
54 #include <tools/simplerm.hxx>
55 
56 #include <tools/isofallback.hxx>
57 
58 #include <functional>
59 #include <algorithm>
60 #include <hash_map>
61 #include <list>
62 #include <set>
63 
64 #ifdef UNX
65 #define SEARCH_PATH_DELIMITER_CHAR_STRING ":"
66 #define SEARCH_PATH_DELIMITER ':'
67 #else
68 #define SEARCH_PATH_DELIMITER_CHAR_STRING ";"
69 #define SEARCH_PATH_DELIMITER ';'
70 #endif
71 
72 #define SEARCH_PATH_DELIMITER_STRING ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SEARCH_PATH_DELIMITER_CHAR_STRING ) )
73 
74 using namespace rtl;
75 using namespace osl;
76 
77 // for thread safety
78 static osl::Mutex* pResMgrMutex = NULL;
79 static osl::Mutex& getResMgrMutex()
80 {
81     if( !pResMgrMutex )
82     {
83         osl::Guard<osl::Mutex> aGuard( *osl::Mutex::getGlobalMutex() );
84         if( ! pResMgrMutex )
85             pResMgrMutex = new osl::Mutex();
86     }
87     return *pResMgrMutex;
88 }
89 
90 struct ImpContent;
91 class InternalResMgr
92 {
93 	friend class ResMgr;
94 	friend class SimpleResMgr;
95     friend class ResMgrContainer;
96 
97 	ImpContent *			        pContent;
98 	sal_uInt32					        nOffCorrection;
99 	sal_uInt8 *					        pStringBlock;
100 	SvStream *				        pStm;
101 	sal_Bool					        bEqual2Content;
102 	sal_uInt32					        nEntries;
103 	OUString				        aFileName;
104     OUString                        aPrefix;
105     OUString                        aResName;
106     bool                            bSingular;
107     com::sun::star::lang::Locale    aLocale;
108 	std::hash_map<sal_uInt64, int>* pResUseDump;
109 
110 							InternalResMgr( const OUString& rFileURL,
111                                             const OUString& aPrefix,
112                                             const OUString& aResName,
113                                             const com::sun::star::lang::Locale& rLocale );
114 							~InternalResMgr();
115 	sal_Bool					Create();
116 
117 	sal_Bool					IsGlobalAvailable( RESOURCE_TYPE nRT, sal_uInt32 nId ) const;
118 	void *					LoadGlobalRes( RESOURCE_TYPE nRT, sal_uInt32 nId,
119 										   void **pResHandle );
120 public:
121 	void					FreeGlobalRes( void *, void * );
122 
123 	SvStream *				GetBitmapStream( sal_uInt32 nResId );
124 };
125 
126 // =======================================================================
127 
128 class ResMgrContainer
129 {
130     static ResMgrContainer*     pOneInstance;
131 
132     struct ContainerElement
133     {
134         InternalResMgr* pResMgr;
135         OUString        aFileURL;
136         int             nRefCount;
137         int             nLoadCount;
138 
139         ContainerElement() :
140             pResMgr( NULL ),
141             nRefCount( 0 ),
142             nLoadCount( 0 )
143             {}
144     };
145 
146     std::hash_map< OUString, ContainerElement, OUStringHash> m_aResFiles;
147     com::sun::star::lang::Locale                             m_aDefLocale;
148 
149     ResMgrContainer() { init(); }
150     ~ResMgrContainer();
151 
152     void init();
153     public:
154 
155     static ResMgrContainer& get();
156     static void release();
157 
158     InternalResMgr* getResMgr( const OUString& rPrefix,
159                                com::sun::star::lang::Locale& rLocale,
160                                bool bForceNewInstance = false
161                                );
162     InternalResMgr* getNextFallback( InternalResMgr* pResMgr );
163 
164     void freeResMgr( InternalResMgr* pResMgr );
165 
166     void setDefLocale( const com::sun::star::lang::Locale& rLocale )
167     { m_aDefLocale = rLocale; }
168     const com::sun::star::lang::Locale& getDefLocale() const
169     { return m_aDefLocale; }
170 };
171 
172 ResMgrContainer* ResMgrContainer::pOneInstance = NULL;
173 
174 ResMgrContainer& ResMgrContainer::get()
175 {
176     if( ! pOneInstance )
177         pOneInstance = new ResMgrContainer();
178     return *pOneInstance;
179 }
180 
181 ResMgrContainer::~ResMgrContainer()
182 {
183     for( std::hash_map< OUString, ContainerElement, OUStringHash >::iterator it =
184             m_aResFiles.begin(); it != m_aResFiles.end(); ++it )
185     {
186         OSL_TRACE( "Resource file %s loaded %d times\n",
187                          OUStringToOString( it->second.aFileURL, osl_getThreadTextEncoding() ).getStr(),
188                          it->second.nLoadCount );
189         delete it->second.pResMgr;
190     }
191 }
192 
193 void ResMgrContainer::release()
194 {
195     delete pOneInstance;
196     pOneInstance = NULL;
197 }
198 
199 void ResMgrContainer::init()
200 {
201     // get resource path
202     std::list< OUString > aDirs;
203     sal_Int32 nIndex = 0;
204 
205     // 1. fixed locations
206     rtl::OUString uri(
207         RTL_CONSTASCII_USTRINGPARAM("$BRAND_BASE_DIR/program/resource"));
208     rtl::Bootstrap::expandMacros(uri);
209     aDirs.push_back(uri);
210     uri = rtl::OUString(
211         RTL_CONSTASCII_USTRINGPARAM("$OOO_BASE_DIR/program/resource"));
212     rtl::Bootstrap::expandMacros(uri);
213     aDirs.push_back(uri);
214 
215     // 2. in STAR_RESOURCEPATH
216     const sal_Char* pEnv = getenv( "STAR_RESOURCEPATH" );
217     if( pEnv )
218     {
219         OUString aEnvPath( OStringToOUString( OString( pEnv ), osl_getThreadTextEncoding() ) );
220         nIndex = 0;
221         while( nIndex >= 0 )
222         {
223             OUString aPathElement( aEnvPath.getToken( 0, SEARCH_PATH_DELIMITER, nIndex ) );
224             if( aPathElement.getLength() )
225             {
226                 OUString aFileURL;
227                 File::getFileURLFromSystemPath( aPathElement, aFileURL );
228                 aDirs.push_back( aFileURL);
229             }
230         }
231     }
232 
233     // collect all possible resource files
234     for( std::list< OUString >::const_iterator dir_it = aDirs.begin(); dir_it != aDirs.end(); ++dir_it )
235     {
236         Directory aDir( *dir_it );
237         if( aDir.open() == FileBase::E_None )
238         {
239             DirectoryItem aItem;
240             while( aDir.getNextItem( aItem ) == FileBase::E_None )
241             {
242                 FileStatus aStatus(FileStatusMask_FileName);
243                 if( aItem.getFileStatus( aStatus ) == FileBase::E_None )
244                 {
245                     OUString aFileName = aStatus.getFileName();
246                     if( aFileName.getLength() < 5 )
247                         continue;
248                     if( ! aFileName.endsWithIgnoreAsciiCaseAsciiL( ".res", 4 ) )
249                         continue;
250                     OUString aResName = aFileName.copy( 0, aFileName.getLength()-4 );
251                     if( m_aResFiles.find( aResName ) != m_aResFiles.end() )
252                         continue;
253                     OUStringBuffer aURL( dir_it->getLength() + aFileName.getLength() + 1 );
254                     aURL.append( *dir_it );
255                     if( !dir_it->endsWithIgnoreAsciiCaseAsciiL( "/", 1 ) )
256                         aURL.append( sal_Unicode('/') );
257                     aURL.append( aFileName );
258                     m_aResFiles[ aResName ].aFileURL = aURL.makeStringAndClear();
259                 }
260             }
261         }
262         #if OSL_DEBUG_LEVEL > 1
263         else
264             OSL_TRACE( "opening dir %s failed\n", OUStringToOString( *dir_it, osl_getThreadTextEncoding() ).getStr() );
265         #endif
266     }
267     #if OSL_DEBUG_LEVEL > 1
268     for( std::hash_map< OUString, ContainerElement, OUStringHash >::const_iterator it =
269             m_aResFiles.begin(); it != m_aResFiles.end(); ++it )
270     {
271         OSL_TRACE( "ResMgrContainer: %s -> %s\n",
272                  OUStringToOString( it->first, osl_getThreadTextEncoding() ).getStr(),
273                  OUStringToOString( it->second.aFileURL, osl_getThreadTextEncoding() ).getStr() );
274     }
275     #endif
276 
277     // set default language
278     LanguageType nLang = MsLangId::getSystemUILanguage();
279     MsLangId::convertLanguageToLocale(nLang, m_aDefLocale);
280 }
281 
282 InternalResMgr* ResMgrContainer::getResMgr( const OUString& rPrefix,
283                                             com::sun::star::lang::Locale& rLocale,
284                                             bool bForceNewInstance
285                                             )
286 {
287     com::sun::star::lang::Locale aLocale( rLocale );
288     OUStringBuffer aSearch( rPrefix.getLength() + 16 );
289     std::hash_map< OUString, ContainerElement, OUStringHash >::iterator it = m_aResFiles.end();
290 
291     int nTries = 0;
292     if( aLocale.Language.getLength() > 0 )
293         nTries = 1;
294     if( aLocale.Country.getLength() > 0 )
295         nTries = 2;
296     if( aLocale.Variant.getLength() > 0 )
297         nTries = 3;
298     while( nTries-- )
299     {
300         aSearch.append( rPrefix );
301         if( nTries > -1 )
302         {
303             aSearch.append( aLocale.Language );
304         }
305         if( nTries > 0 )
306         {
307             aSearch.append( sal_Unicode('-') );
308             aSearch.append( aLocale.Country );
309         }
310         if( nTries > 1 )
311         {
312             aSearch.append( sal_Unicode('-') );
313             aSearch.append( aLocale.Variant );
314         }
315         it = m_aResFiles.find( aSearch.makeStringAndClear() );
316         if( it != m_aResFiles.end() )
317         {
318             // ensure InternalResMgr existance
319             if( ! it->second.pResMgr )
320             {
321                 InternalResMgr* pImp =
322                     new InternalResMgr( it->second.aFileURL, rPrefix, it->first, aLocale );
323                 if( ! pImp->Create() )
324                 {
325                     delete pImp;
326                     continue;
327                 }
328                 it->second.pResMgr = pImp;
329             }
330             break;
331         }
332         if( nTries == 0 && !aLocale.Language.equalsIgnoreAsciiCaseAscii( "en" ) )
333         {
334             // locale fallback failed
335             // fallback to en-US locale
336             nTries = 2;
337             aLocale.Language = OUString( RTL_CONSTASCII_USTRINGPARAM( "en" ) );
338             aLocale.Country  = OUString( RTL_CONSTASCII_USTRINGPARAM( "US" ) );
339             aLocale.Variant = OUString();
340         }
341     }
342     // try if there is anything with this prefix at all
343     if( it == m_aResFiles.end() )
344     {
345         aLocale = com::sun::star::lang::Locale();
346         it = m_aResFiles.find( rPrefix );
347         if( it == m_aResFiles.end() )
348         {
349             for( it = m_aResFiles.begin(); it != m_aResFiles.end(); ++it )
350             {
351                 if( it->first.matchIgnoreAsciiCase( rPrefix ) )
352                 {
353                     // ensure InternalResMgr existance
354                     if( ! it->second.pResMgr )
355                     {
356                         InternalResMgr* pImp =
357                             new InternalResMgr( it->second.aFileURL,
358                                                 rPrefix,
359                                                 it->first,
360                                                 aLocale );
361                         if( ! pImp->Create() )
362                         {
363                             delete pImp;
364                             continue;
365                         }
366                         it->second.pResMgr = pImp;
367                     }
368                     // try to guess locale
369                     sal_Int32 nIndex = rPrefix.getLength();
370                     aLocale.Language = it->first.getToken( 0, '-', nIndex );
371                     if( nIndex > 0 )
372                         aLocale.Country = it->first.getToken( 0, '-', nIndex );
373                     if( nIndex > 0 )
374                         aLocale.Variant = it->first.getToken( 0, '-', nIndex );
375                     break;
376                 }
377             }
378         }
379     }
380     // give up
381     if( it == m_aResFiles.end() )
382     {
383         OUStringBuffer sKey = rPrefix;
384         sKey.append( rLocale.Language );
385         if( rLocale.Country.getLength() )
386         {
387             sKey.append( sal_Unicode('-') );
388             sKey.append( rLocale.Country );
389         }
390         if( rLocale.Variant.getLength() )
391         {
392             sKey.append( sal_Unicode('-') );
393             sKey.append( rLocale.Variant );
394         } // if( aLocale.Variant.getLength() )
395         ::rtl::OUString sURL = sKey.makeStringAndClear();
396         sURL += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".res"));
397         if ( m_aResFiles.find(sURL) == m_aResFiles.end() )
398         {
399             m_aResFiles[ sURL ].aFileURL = sURL;
400             return getResMgr(rPrefix,rLocale,bForceNewInstance);
401         } // if ( m_aResFiles.find(sURL) == m_aResFiles.end() )
402         return NULL;
403     }
404 
405     rLocale = aLocale;
406     // at this point it->second.pResMgr must be filled either by creating a new one
407     // (then the refcount is still 0) or because we already had one
408     InternalResMgr* pImp = it->second.pResMgr;
409 
410     if( it->second.nRefCount == 0 )
411         it->second.nLoadCount++;
412 
413     // for SimpleResMgr
414     if( bForceNewInstance )
415     {
416         if( it->second.nRefCount == 0 )
417         {
418             // shortcut: the match algorithm already created the InternalResMgr
419             // take it instead of creating yet another one
420             it->second.pResMgr = NULL;
421             pImp->bSingular = true;
422         }
423         else
424         {
425             pImp = new InternalResMgr( it->second.aFileURL, rPrefix, it->first, aLocale );
426             pImp->bSingular = true;
427             if( !pImp->Create() )
428             {
429                 delete pImp;
430                 pImp = NULL;
431             }
432             else
433                 it->second.nLoadCount++;
434         }
435     }
436     else
437         it->second.nRefCount++;
438 
439     return pImp;
440 }
441 
442 InternalResMgr* ResMgrContainer::getNextFallback( InternalResMgr* pMgr )
443 {
444     com::sun::star::lang::Locale aLocale = pMgr->aLocale;
445     if( aLocale.Variant.getLength() )
446         aLocale.Variant = OUString();
447     else if( aLocale.Country.getLength() )
448         aLocale.Country = OUString();
449     else if( ! aLocale.Language.equalsIgnoreAsciiCaseAscii( "en" ) )
450     {
451         aLocale.Language = OUString( RTL_CONSTASCII_USTRINGPARAM( "en" ) );
452         aLocale.Country = OUString( RTL_CONSTASCII_USTRINGPARAM( "US" ) );
453     }
454     InternalResMgr* pNext = getResMgr( pMgr->aPrefix, aLocale, pMgr->bSingular );
455     // prevent recursion
456     if( pNext == pMgr || pNext->aResName.equals( pMgr->aResName ) )
457     {
458         if( pNext->bSingular )
459             delete pNext;
460         pNext = NULL;
461     }
462     return pNext;
463 }
464 
465 void ResMgrContainer::freeResMgr( InternalResMgr* pResMgr )
466 {
467     if( pResMgr->bSingular )
468         delete pResMgr;
469     else
470     {
471         std::hash_map< OUString, ContainerElement, OUStringHash >::iterator it =
472         m_aResFiles.find( pResMgr->aResName );
473         if( it != m_aResFiles.end() )
474         {
475             DBG_ASSERT( it->second.nRefCount > 0, "InternalResMgr freed too often" );
476             if( it->second.nRefCount > 0 )
477                 it->second.nRefCount--;
478             if( it->second.nRefCount == 0 )
479             {
480                 delete it->second.pResMgr;
481                 it->second.pResMgr = NULL;
482             }
483         }
484     }
485 }
486 
487 // =======================================================================
488 
489 void Resource::TestRes()
490 {
491     if( m_pResMgr )
492         m_pResMgr->TestStack( this );
493 }
494 
495 struct ImpContent
496 {
497     sal_uInt64   nTypeAndId;
498     sal_uInt32   nOffset;
499 };
500 
501 struct ImpContentLessCompare : public ::std::binary_function< ImpContent, ImpContent, bool>
502 {
503 	inline bool operator() (const ImpContent& lhs, const ImpContent& rhs) const
504 	{
505 		return lhs.nTypeAndId < rhs.nTypeAndId;
506 	}
507 };
508 
509 struct ImpContentMixLessCompare : public ::std::binary_function< ImpContent, sal_uInt64, bool>
510 {
511 	inline bool operator() (const ImpContent& lhs, const sal_uInt64& rhs) const
512 	{
513 		return lhs.nTypeAndId < rhs;
514 	}
515 	inline bool operator() (const sal_uInt64& lhs, const ImpContent& rhs) const
516 	{
517 		return lhs < rhs.nTypeAndId;
518 	}
519 };
520 
521 
522 // =======================================================================
523 
524 static ResHookProc pImplResHookProc = 0;
525 
526 // =======================================================================
527 
528 SvStream * InternalResMgr::GetBitmapStream( sal_uInt32 nId )
529 {
530     // Anfang der Strings suchen
531 	ImpContent * pFind = ::std::lower_bound(pContent,
532 											pContent + nEntries,
533 											((sal_uInt64(RT_SYS_BITMAP) << 32) | nId),
534 											ImpContentMixLessCompare());
535 	if ( (pFind != (pContent + nEntries)) && (pFind->nTypeAndId == ((sal_uInt64(RT_SYS_BITMAP) << 32) | nId)) )
536 	{
537 		pStm->Seek( pFind->nOffset );
538         return pStm;
539 	}
540     return NULL;
541 }
542 
543 // -----------------------------------------------------------------------
544 
545 InternalResMgr::InternalResMgr( const OUString& rFileURL,
546                                 const OUString& rPrefix,
547                                 const OUString& rResName,
548                                 const com::sun::star::lang::Locale& rLocale )
549     : pContent( NULL )
550     , pStringBlock( NULL )
551     , pStm( NULL )
552     , bEqual2Content( sal_True )
553     , nEntries( 0 )
554     , aFileName( rFileURL )
555     , aPrefix( rPrefix )
556     , aResName( rResName )
557     , bSingular( false )
558     , aLocale( rLocale )
559     , pResUseDump( 0 )
560 {
561 }
562 
563 // -----------------------------------------------------------------------
564 
565 InternalResMgr::~InternalResMgr()
566 {
567     rtl_freeMemory(pContent);
568     rtl_freeMemory(pStringBlock);
569     delete pStm;
570 
571 #ifdef DBG_UTIL
572     if( pResUseDump )
573     {
574         const sal_Char* pLogFile = getenv( "STAR_RESOURCE_LOGGING" );
575         if ( pLogFile )
576         {
577             SvFileStream aStm( UniString( pLogFile, RTL_TEXTENCODING_ASCII_US ), STREAM_WRITE );
578             aStm.Seek( STREAM_SEEK_TO_END );
579             ByteString aLine( "FileName: " );
580             aLine.Append( ByteString( OUStringToOString( aFileName, RTL_TEXTENCODING_UTF8 ) ) );
581             aStm.WriteLine( aLine );
582 
583             for( std::hash_map<sal_uInt64, int>::const_iterator it = pResUseDump->begin();
584                  it != pResUseDump->end(); ++it )
585             {
586                 sal_uInt64 nKeyId = it->first;
587                 aLine.Assign( "Type/Id: " );
588                 aLine.Append( ByteString::CreateFromInt32( sal::static_int_cast< sal_Int32 >((nKeyId >> 32) & 0xFFFFFFFF) ) );
589                 aLine.Append( '/' );
590                 aLine.Append( ByteString::CreateFromInt32( sal::static_int_cast< sal_Int32 >(nKeyId & 0xFFFFFFFF) ) );
591                 aStm.WriteLine( aLine );
592             }
593         }
594     }
595 #endif
596 
597     delete pResUseDump;
598 }
599 
600 // -----------------------------------------------------------------------
601 
602 
603 sal_Bool InternalResMgr::Create()
604 {
605     ResMgrContainer::get();
606     sal_Bool bDone = sal_False;
607 
608     pStm = new SvFileStream( aFileName, (STREAM_READ | STREAM_SHARE_DENYWRITE | STREAM_NOCREATE) );
609     if( pStm->GetError() == 0 )
610     {
611         sal_Int32   lContLen = 0;
612 
613         pStm->Seek( STREAM_SEEK_TO_END );
614         /*
615         if( ( pInternalResMgr->pHead = (RSHEADER_TYPE *)mmap( 0, nResourceFileSize,
616                                                         PROT_READ, MAP_PRIVATE,
617                                                         fRes, 0 ) ) != (RSHEADER_TYPE *)-1)
618                                                         */
619         pStm->SeekRel( - (int)sizeof( lContLen ) );
620         pStm->Read( &lContLen, sizeof( lContLen ) );
621         // is bigendian, swab to the right endian
622         lContLen = ResMgr::GetLong( &lContLen );
623         pStm->SeekRel( -lContLen );
624         // allocate stored ImpContent data (12 bytes per unit)
625         sal_uInt8* pContentBuf = (sal_uInt8*)rtl_allocateMemory( lContLen );
626         pStm->Read( pContentBuf, lContLen );
627         // allocate ImpContent space (sizeof(ImpContent) per unit, not necessarily 12)
628         pContent = (ImpContent *)rtl_allocateMemory( sizeof(ImpContent)*lContLen/12 );
629         // Auf die Anzahl der ImpContent k�rzen
630         nEntries = (sal_uInt32)lContLen / 12;
631         bEqual2Content = sal_True;  // Die Daten der Resourcen liegen
632                                 // genauso wie das Inhaltsverzeichnis
633         sal_Bool bSorted = sal_True;
634         if( nEntries )
635         {
636 #ifdef DBG_UTIL
637             const sal_Char* pLogFile = getenv( "STAR_RESOURCE_LOGGING" );
638             if ( pLogFile )
639             {
640                 pResUseDump = new std::hash_map<sal_uInt64, int>;
641                 for( sal_uInt32 i = 0; i < nEntries; ++i )
642                     (*pResUseDump)[pContent[i].nTypeAndId] = 1;
643             }
644 #endif
645             // swap the content to the right endian
646             pContent[0].nTypeAndId = ResMgr::GetUInt64( pContentBuf );
647             pContent[0].nOffset = ResMgr::GetLong( pContentBuf+8 );
648 			sal_uInt32 nCount = nEntries - 1;
649             for( sal_uInt32 i = 0,j=1; i < nCount; ++i,++j )
650             {
651                 // swap the content to the right endian
652                 pContent[j].nTypeAndId = ResMgr::GetUInt64( pContentBuf + (12*j) );
653                 pContent[j].nOffset = ResMgr::GetLong( pContentBuf + (12*j+8) );
654                 if( pContent[i].nTypeAndId >= pContent[j].nTypeAndId )
655                     bSorted = sal_False;
656                 if( (pContent[i].nTypeAndId & 0xFFFFFFFF00000000LL) == (pContent[j].nTypeAndId & 0xFFFFFFFF00000000LL)
657 					&& pContent[i].nOffset >= pContent[j].nOffset )
658                     bEqual2Content = sal_False;
659             }
660         }
661         rtl_freeMemory( pContentBuf );
662 #ifndef OS2
663         OSL_ENSURE( bSorted, "content not sorted" );
664 #endif
665         OSL_ENSURE( bEqual2Content, "resource structure wrong" );
666         if( !bSorted )
667 			::std::sort(pContent,pContent+nEntries,ImpContentLessCompare());
668             //	qsort( pContent, nEntries, sizeof( ImpContent ), Compare );
669 
670         bDone = sal_True;
671     }
672 
673     return bDone;
674 }
675 
676 // -----------------------------------------------------------------------
677 
678 sal_Bool InternalResMgr::IsGlobalAvailable( RESOURCE_TYPE nRT, sal_uInt32 nId ) const
679 {
680     // Anfang der Strings suchen
681 	sal_uInt64 nValue = ((sal_uInt64(nRT) << 32) | nId);
682 	ImpContent * pFind = ::std::lower_bound(pContent,
683 											pContent + nEntries,
684 											nValue,
685 											ImpContentMixLessCompare());
686     return (pFind != (pContent + nEntries)) && (pFind->nTypeAndId == nValue);
687 }
688 
689 // -----------------------------------------------------------------------
690 
691 void* InternalResMgr::LoadGlobalRes( RESOURCE_TYPE nRT, sal_uInt32 nId,
692                                      void **pResHandle )
693 {
694 #ifdef DBG_UTIL
695     if( pResUseDump )
696         pResUseDump->erase( (sal_uInt64(nRT) << 32) | nId );
697 #endif
698     // Anfang der Strings suchen
699 	sal_uInt64 nValue = ((sal_uInt64(nRT) << 32) | nId);
700 	ImpContent* pEnd = (pContent + nEntries);
701 	ImpContent* pFind = ::std::lower_bound(	pContent,
702 											pEnd,
703 											nValue,
704 											ImpContentMixLessCompare());
705     if( pFind && (pFind != pEnd) && (pFind->nTypeAndId == nValue) )
706 	{
707 		if( nRT == RSC_STRING && bEqual2Content )
708 		{
709 			// String Optimierung
710 			if( !pStringBlock )
711 			{
712 				// Anfang der Strings suchen
713 				ImpContent * pFirst = pFind;
714 				ImpContent * pLast = pFirst;
715 				while( pFirst > pContent && ((pFirst -1)->nTypeAndId >> 32) == RSC_STRING )
716 					--pFirst;
717 				while( pLast < pEnd && (pLast->nTypeAndId >> 32) == RSC_STRING )
718 					++pLast;
719 				nOffCorrection = pFirst->nOffset;
720 				sal_uInt32 nSize;
721 				--pLast;
722 				pStm->Seek( pLast->nOffset );
723 				RSHEADER_TYPE aHdr;
724 				pStm->Read( &aHdr, sizeof( aHdr ) );
725 				nSize = pLast->nOffset + aHdr.GetGlobOff() - nOffCorrection;
726 				pStringBlock = (sal_uInt8*)rtl_allocateMemory( nSize );
727 				pStm->Seek( pFirst->nOffset );
728 				pStm->Read( pStringBlock, nSize );
729 			}
730 			*pResHandle = pStringBlock;
731 			return (sal_uInt8*)pStringBlock + pFind->nOffset - nOffCorrection;
732 		} // if( nRT == RSC_STRING && bEqual2Content )
733 		else
734 		{
735 			*pResHandle = 0;
736 			RSHEADER_TYPE aHeader;
737 			pStm->Seek( pFind->nOffset );
738 			pStm->Read( &aHeader, sizeof( RSHEADER_TYPE ) );
739 			void * pRes = rtl_allocateMemory( aHeader.GetGlobOff() );
740 			memcpy( pRes, &aHeader, sizeof( RSHEADER_TYPE ) );
741 			pStm->Read( (sal_uInt8*)pRes + sizeof( RSHEADER_TYPE ),
742 						aHeader.GetGlobOff() - sizeof( RSHEADER_TYPE ) );
743 			return pRes;
744 		}
745 	} // if( pFind && (pFind != pEnd) && (pFind->nTypeAndId == nValue) )
746 	*pResHandle = 0;
747     //Resource holen
748     return NULL;
749 }
750 
751 // -----------------------------------------------------------------------
752 
753 void InternalResMgr::FreeGlobalRes( void * pResHandle, void * pResource )
754 {
755     if ( !pResHandle )
756         // REsource wurde extra allokiert
757         rtl_freeMemory(pResource);
758 }
759 
760 // =======================================================================
761 
762 #ifdef DBG_UTIL
763 
764 UniString GetTypeRes_Impl( const ResId& rTypeId )
765 {
766     // Funktion verlassen, falls Resourcefehler in dieser Funktion
767     static int bInUse = sal_False;
768     UniString aTypStr( UniString::CreateFromInt32( rTypeId.GetId() ) );
769 
770     if ( !bInUse )
771     {
772         bInUse = sal_True;
773 
774         ResId aResId( sal_uInt32(RSCVERSION_ID), *rTypeId.GetResMgr() );
775         aResId.SetRT( RSC_VERSIONCONTROL );
776 
777         if ( rTypeId.GetResMgr()->GetResource( aResId ) )
778         {
779             rTypeId.SetRT( RSC_STRING );
780             if ( rTypeId.GetResMgr()->IsAvailable( rTypeId ) )
781             {
782                 aTypStr = UniString( rTypeId );
783                 // Versions Resource Klassenzeiger ans Ende setzen
784                 rTypeId.GetResMgr()->Increment( sizeof( RSHEADER_TYPE ) );
785             }
786         }
787         bInUse = sal_False;
788     }
789 
790     return aTypStr;
791 }
792 
793 // -----------------------------------------------------------------------
794 
795 void ResMgr::RscError_Impl( const sal_Char* pMessage, ResMgr* pResMgr,
796                             RESOURCE_TYPE nRT, sal_uInt32 nId,
797                             std::vector< ImpRCStack >& rResStack, int nDepth )
798 {
799     // create a separate ResMgr with its own stack
800     // first get a second reference of the InternalResMgr
801     InternalResMgr* pImp =
802         ResMgrContainer::get().getResMgr( pResMgr->pImpRes->aPrefix,
803                                           pResMgr->pImpRes->aLocale,
804                                           true );
805 
806     ResMgr* pNewResMgr = new ResMgr( pImp );
807 
808     ByteString aStr = OUStringToOString( pResMgr->GetFileName(), RTL_TEXTENCODING_UTF8 );
809     if ( aStr.Len() )
810         aStr += '\n';
811 
812     aStr.Append( "Class: " );
813     aStr.Append( ByteString( GetTypeRes_Impl( ResId( nRT, *pNewResMgr ) ), RTL_TEXTENCODING_UTF8 ) );
814     aStr.Append( ", Id: " );
815     aStr.Append( ByteString::CreateFromInt32( (long)nId ) );
816     aStr.Append( ". " );
817     aStr.Append( pMessage );
818 
819     aStr.Append( "\nResource Stack\n" );
820     while( nDepth > 0 )
821     {
822         aStr.Append( "Class: " );
823         aStr.Append( ByteString( GetTypeRes_Impl( ResId( rResStack[nDepth].pResource->GetRT(), *pNewResMgr ) ), RTL_TEXTENCODING_UTF8 ) );
824         aStr.Append( ", Id: " );
825         aStr.Append( ByteString::CreateFromInt32( (long)rResStack[nDepth].pResource->GetId() ) );
826         nDepth--;
827     }
828 
829     // clean up
830     delete pNewResMgr;
831 
832     DBG_ERROR( aStr.GetBuffer() );
833 }
834 
835 #endif
836 
837 // =======================================================================
838 
839 static void RscException_Impl()
840 {
841     switch ( vos::OSignalHandler::raise( OSL_SIGNAL_USER_RESOURCEFAILURE, (void*)"" ) )
842     {
843         case vos::OSignalHandler::TAction_CallNextHandler:
844             abort();
845 
846         case vos::OSignalHandler::TAction_Ignore:
847             return;
848 
849         case vos::OSignalHandler::TAction_AbortApplication:
850             abort();
851 
852         case vos::OSignalHandler::TAction_KillApplication:
853             exit(-1);
854     }
855 }
856 
857 // =======================================================================
858 
859 void ImpRCStack::Init( ResMgr* pMgr, const Resource* pObj, sal_uInt32 Id )
860 {
861     pResource       = NULL;
862     pClassRes       = NULL;
863     Flags           = RC_NOTYPE;
864     aResHandle      = NULL;
865     pResObj         = pObj;
866     nId             = Id & ~RSC_DONTRELEASE; //TLX: Besser Init aendern
867     pResMgr         = pMgr;
868     if ( !(Id & RSC_DONTRELEASE) )
869         Flags      |= RC_AUTORELEASE;
870 }
871 
872 // -----------------------------------------------------------------------
873 
874 void ImpRCStack::Clear()
875 {
876     pResource       = NULL;
877     pClassRes       = NULL;
878     Flags           = RC_NOTYPE;
879     aResHandle      = NULL;
880     pResObj         = NULL;
881     nId             = 0;
882     pResMgr         = NULL;
883 }
884 
885 // -----------------------------------------------------------------------
886 
887 static RSHEADER_TYPE* LocalResource( const ImpRCStack* pStack,
888                                      RESOURCE_TYPE nRTType,
889                                      sal_uInt32 nId )
890 {
891     // Gibt die Position der Resource zurueck, wenn sie gefunden wurde.
892     // Ansonsten gibt die Funktion Null zurueck.
893     RSHEADER_TYPE*  pTmp;   // Zeiger auf Kind-Resourceobjekte
894     RSHEADER_TYPE*  pEnd;   // Zeiger auf das Ende der Resource
895 
896     if ( pStack->pResource && pStack->pClassRes )
897     {
898         pTmp = (RSHEADER_TYPE*)
899                ((sal_uInt8*)pStack->pResource + pStack->pResource->GetLocalOff());
900         pEnd = (RSHEADER_TYPE*)
901                ((sal_uInt8*)pStack->pResource + pStack->pResource->GetGlobOff());
902         while ( pTmp != pEnd )
903         {
904             if ( pTmp->GetRT() == nRTType && pTmp->GetId() == nId )
905                 return pTmp;
906             pTmp = (RSHEADER_TYPE*)((sal_uInt8*)pTmp + pTmp->GetGlobOff());
907         }
908     }
909 
910     return NULL;
911 }
912 
913 // =======================================================================
914 
915 void* ResMgr::pEmptyBuffer = NULL;
916 
917 void* ResMgr::getEmptyBuffer()
918 {
919     if( ! pEmptyBuffer )
920         pEmptyBuffer = rtl_allocateZeroMemory( 1024 );
921     return pEmptyBuffer;
922 }
923 
924 void ResMgr::DestroyAllResMgr()
925 {
926     {
927         osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
928         if( pEmptyBuffer )
929         {
930             rtl_freeMemory( pEmptyBuffer );
931             pEmptyBuffer = NULL;
932         }
933         ResMgrContainer::release();
934     }
935     delete pResMgrMutex;
936     pResMgrMutex = NULL;
937 }
938 
939 // -----------------------------------------------------------------------
940 
941 void ResMgr::Init( const OUString& rFileName )
942 {
943     (void) rFileName; // avoid warning about unused parameter
944     osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
945 
946     if ( !pImpRes )
947     {
948 #ifdef DBG_UTIL
949         ByteString aStr( "Resourcefile not found:\n" );
950         aStr += ByteString( OUStringToOString( rFileName, RTL_TEXTENCODING_UTF8 ) );
951         DBG_ERROR( aStr.GetBuffer() );
952 #endif
953         RscException_Impl();
954     }
955 #ifdef DBG_UTIL
956     else
957     {
958         void* aResHandle = 0;     // Hilfvariable fuer Resource
959         void* pVoid;              // Zeiger auf die Resource
960 
961         pVoid = pImpRes->LoadGlobalRes( RSC_VERSIONCONTROL, RSCVERSION_ID,
962                                         &aResHandle );
963         if ( pVoid )
964             pImpRes->FreeGlobalRes( aResHandle, pVoid );
965         else
966         {
967             ByteString aStr( "Wrong version:\n" );
968             aStr += ByteString( OUStringToOString( pImpRes->aFileName, RTL_TEXTENCODING_UTF8 ) );
969             DbgError( aStr.GetBuffer() );
970         }
971     }
972 #endif
973     nCurStack = -1;
974     aStack.clear();
975     pFallbackResMgr = pOriginalResMgr = NULL;
976     incStack();
977 }
978 
979 // -----------------------------------------------------------------------
980 
981 ResMgr::ResMgr( InternalResMgr * pImpMgr )
982 {
983     pImpRes = pImpMgr;
984     Init( pImpMgr->aFileName );
985 }
986 
987 // -----------------------------------------------------------------------
988 
989 ResMgr::~ResMgr()
990 {
991     osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
992 
993     ResMgrContainer::get().freeResMgr( pImpRes );
994 
995     // clean up possible left rc stack frames
996     while( nCurStack > 0 )
997     {
998         if( ( aStack[nCurStack].Flags & (RC_GLOBAL | RC_NOTFOUND) ) == RC_GLOBAL )
999             pImpRes->FreeGlobalRes( aStack[nCurStack].aResHandle,
1000                                     aStack[nCurStack].pResource );
1001         nCurStack--;
1002     }
1003 }
1004 
1005 
1006 void ResMgr::incStack()
1007 {
1008     nCurStack++;
1009     if( nCurStack >= int(aStack.size()) )
1010         aStack.push_back( ImpRCStack() );
1011     aStack[nCurStack].Clear();
1012 
1013     DBG_ASSERT( nCurStack < 32, "Resource stack unreasonably large" );
1014 }
1015 
1016 void ResMgr::decStack()
1017 {
1018     DBG_ASSERT( nCurStack > 0, "resource stack underrun  !" );
1019     if( (aStack[nCurStack].Flags & RC_FALLBACK_UP) )
1020     {
1021         nCurStack--;
1022         // warning: this will delete *this, see below
1023         pOriginalResMgr->decStack();
1024     }
1025     else
1026     {
1027         ImpRCStack& rTop = aStack[nCurStack];
1028         if( (rTop.Flags & RC_FALLBACK_DOWN) )
1029         {
1030             #if OSL_DEBUG_LEVEL > 1
1031             OSL_TRACE( "returning from fallback %s\n",
1032                      OUStringToOString(pFallbackResMgr->GetFileName(), osl_getThreadTextEncoding() ).getStr() );
1033             #endif
1034             delete pFallbackResMgr;
1035             pFallbackResMgr = NULL;
1036         }
1037         nCurStack--;
1038     }
1039 }
1040 
1041 #ifdef DBG_UTIL
1042 
1043 void ResMgr::TestStack( const Resource* pResObj )
1044 {
1045     osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1046 
1047     if ( DbgIsResource() )
1048     {
1049         for( int i = 1; i <= nCurStack; ++i )
1050         {
1051             if ( aStack[i].pResObj == pResObj )
1052             {
1053 #ifdef DBG_UTIL
1054                 RscError_Impl( "Resource not freed! ", this,
1055                                aStack[i].pResource->GetRT(),
1056                                aStack[i].pResource->GetId(),
1057                                aStack, i-1 );
1058 #endif
1059             }
1060         }
1061     }
1062 }
1063 
1064 #else
1065 
1066 void ResMgr::TestStack( const Resource* )
1067 {
1068 }
1069 
1070 #endif
1071 
1072 // -----------------------------------------------------------------------
1073 sal_Bool ResMgr::IsAvailable( const ResId& rId, const Resource* pResObj ) const
1074 {
1075     osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1076 
1077     sal_Bool            bAvailable = sal_False;
1078     RSHEADER_TYPE*  pClassRes = rId.GetpResource();
1079     RESOURCE_TYPE   nRT = rId.GetRT2();
1080     sal_uInt32      nId = rId.GetId();
1081     const ResMgr*   pMgr = rId.GetResMgr();
1082 
1083     if ( !pMgr )
1084         pMgr = this;
1085 
1086     if( pMgr->pFallbackResMgr )
1087     {
1088         ResId aId( rId );
1089         aId.SetResMgr( NULL );
1090         return pMgr->pFallbackResMgr->IsAvailable( aId, pResObj );
1091     }
1092 
1093     if ( !pResObj || pResObj == pMgr->aStack[pMgr->nCurStack].pResObj )
1094     {
1095         if ( !pClassRes )
1096             pClassRes = LocalResource( &pMgr->aStack[pMgr->nCurStack], nRT, nId );
1097         if ( pClassRes )
1098         {
1099             if ( pClassRes->GetRT() == nRT )
1100                 bAvailable = sal_True;
1101         }
1102     }
1103 
1104     // vieleicht globale Resource
1105     if ( !pClassRes )
1106         bAvailable = pMgr->pImpRes->IsGlobalAvailable( nRT, nId );
1107 
1108     return bAvailable;
1109 }
1110 
1111 // -----------------------------------------------------------------------
1112 
1113 void* ResMgr::GetClass()
1114 {
1115     osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1116 
1117     if( pFallbackResMgr )
1118         return pFallbackResMgr->GetClass();
1119 
1120     return aStack[nCurStack].pClassRes;
1121 }
1122 
1123 // -----------------------------------------------------------------------
1124 
1125 sal_Bool ResMgr::GetResource( const ResId& rId, const Resource* pResObj )
1126 {
1127     osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1128 
1129     if( pFallbackResMgr )
1130     {
1131         ResId aId( rId );
1132         aId.SetResMgr( NULL );
1133         return pFallbackResMgr->GetResource( aId, pResObj );
1134     }
1135 
1136     ResMgr* pMgr = rId.GetResMgr();
1137     if ( pMgr && (this != pMgr) )
1138         return pMgr->GetResource( rId, pResObj );
1139 
1140     // normally Increment will pop the context; this is
1141     // not possible in RC_NOTFOUND case, so pop a frame here
1142     ImpRCStack* pTop = &aStack[nCurStack];
1143     if( (pTop->Flags & RC_NOTFOUND) )
1144     {
1145         decStack();
1146     }
1147 
1148     RSHEADER_TYPE*  pClassRes = rId.GetpResource();
1149     RESOURCE_TYPE   nRT = rId.GetRT2();
1150     sal_uInt32      nId = rId.GetId();
1151 
1152     incStack();
1153     pTop = &aStack[nCurStack];
1154     pTop->Init( pMgr, pResObj, nId |
1155                 (rId.IsAutoRelease() ? 0 : RSC_DONTRELEASE) );
1156 
1157     if ( pClassRes )
1158     {
1159         if ( pClassRes->GetRT() == nRT )
1160             pTop->pClassRes = pClassRes;
1161         else
1162         {
1163 #ifdef DBG_UTIL
1164             RscError_Impl( "Different class and resource type!",
1165                            this, nRT, nId, aStack, nCurStack-1 );
1166 #endif
1167             pTop->Flags |= RC_NOTFOUND;
1168             pTop->pClassRes = getEmptyBuffer();
1169             pTop->pResource = (RSHEADER_TYPE*)pTop->pClassRes;
1170             return sal_False;
1171         }
1172     }
1173     else
1174     {
1175         OSL_ENSURE( nCurStack > 0, "stack of 1 to shallow" );
1176         pTop->pClassRes = LocalResource( &aStack[nCurStack-1], nRT, nId );
1177     }
1178 
1179     if ( pTop->pClassRes )
1180         // lokale Resource, nicht system Resource
1181         pTop->pResource = (RSHEADER_TYPE *)pTop->pClassRes;
1182     else
1183     {
1184         pTop->pClassRes = pImpRes->LoadGlobalRes( nRT, nId, &pTop->aResHandle );
1185         if ( pTop->pClassRes )
1186         {
1187             pTop->Flags |= RC_GLOBAL;
1188             pTop->pResource = (RSHEADER_TYPE *)pTop->pClassRes;
1189         }
1190         else
1191         {
1192             // try to get a fallback resource
1193             pFallbackResMgr = CreateFallbackResMgr( rId, pResObj );
1194             if( pFallbackResMgr )
1195             {
1196                 pTop->Flags |= RC_FALLBACK_DOWN;
1197                 #ifdef DBG_UTIL
1198                 ByteString aMess( "found resource " );
1199                 aMess.Append( ByteString::CreateFromInt32( nId ) );
1200                 aMess.Append( " in fallback " );
1201                 aMess.Append( ByteString( OUStringToOString( pFallbackResMgr->GetFileName(), osl_getThreadTextEncoding() ) ) );
1202                 aMess.Append( "\n" );
1203                 RscError_Impl( aMess.GetBuffer(),
1204                               this, nRT, nId, aStack, nCurStack-1 );
1205                 #endif
1206             }
1207             else
1208             {
1209                 #ifdef DBG_UTIL
1210                 RscError_Impl( "Cannot load resource! ",
1211                               this, nRT, nId, aStack, nCurStack-1 );
1212                 #endif
1213                 pTop->Flags |= RC_NOTFOUND;
1214                 pTop->pClassRes = getEmptyBuffer();
1215                 pTop->pResource = (RSHEADER_TYPE*)pTop->pClassRes;
1216                 return sal_False;
1217             }
1218         }
1219     }
1220 
1221     return sal_True;
1222 }
1223 
1224 // -----------------------------------------------------------------------
1225 
1226 void * ResMgr::GetResourceSkipHeader( const ResId& rResId, ResMgr ** ppResMgr )
1227 {
1228     osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1229 
1230     DBG_ASSERT( rResId.GetResMgr(), "illegal ResId without ResMgr" );
1231     *ppResMgr = rResId.GetResMgr();
1232     if( *ppResMgr )
1233     {
1234         (*ppResMgr)->GetResource( rResId );
1235         (*ppResMgr)->Increment( sizeof( RSHEADER_TYPE ) );
1236         return (*ppResMgr)->GetClass();
1237     }
1238     return getEmptyBuffer();
1239 }
1240 
1241 // -----------------------------------------------------------------------
1242 
1243 void ResMgr::PopContext( const Resource* pResObj )
1244 {
1245     osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1246 
1247     if( pFallbackResMgr )
1248     {
1249         pFallbackResMgr->PopContext( pResObj );
1250         return;
1251     }
1252 
1253 #ifdef DBG_UTIL
1254     if ( DbgIsResource() )
1255     {
1256         if ( (aStack[nCurStack].pResObj != pResObj) || nCurStack == 0 )
1257         {
1258             RscError_Impl( "Cannot free resource! ", this,
1259                            RSC_NOTYPE, 0, aStack, nCurStack );
1260         }
1261     }
1262 #endif
1263 
1264     if ( nCurStack > 0 )
1265     {
1266         ImpRCStack* pTop = &aStack[nCurStack];
1267 #ifdef DBG_UTIL
1268         if ( DbgIsResource() && !(pTop->Flags & RC_NOTFOUND) )
1269         {
1270             void* pRes = (sal_uInt8*)pTop->pResource +
1271                          pTop->pResource->GetLocalOff();
1272 
1273             if ( pTop->pClassRes != pRes )
1274             {
1275                 RscError_Impl( "Classpointer not at the end!",
1276                                this, pTop->pResource->GetRT(),
1277                                pTop->pResource->GetId(),
1278                                aStack, nCurStack-1 );
1279             }
1280         }
1281 #endif
1282 
1283         // Resource freigeben
1284         if( (pTop->Flags & (RC_GLOBAL | RC_NOTFOUND)) == RC_GLOBAL )
1285             // kann auch Fremd-Ressource sein
1286             pImpRes->FreeGlobalRes( pTop->aResHandle, pTop->pResource );
1287         decStack();
1288     }
1289 }
1290 
1291 // -----------------------------------------------------------------------
1292 
1293 RSHEADER_TYPE* ResMgr::CreateBlock( const ResId& rId )
1294 {
1295     osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1296 
1297     if( pFallbackResMgr )
1298     {
1299         ResId aId( rId );
1300         aId.SetResMgr( NULL );
1301         return pFallbackResMgr->CreateBlock( aId );
1302     }
1303 
1304     RSHEADER_TYPE* pHeader = NULL;
1305     if ( GetResource( rId ) )
1306     {
1307         // Der Zeiger steht am Anfang, deswegen zeigt der Klassen-Pointer
1308         // auf den Header und die restliche Groesse ist die Gesammte.
1309         pHeader = (RSHEADER_TYPE*)rtl_allocateMemory( GetRemainSize() );
1310         memcpy( pHeader, GetClass(), GetRemainSize() );
1311         Increment( pHeader->GetLocalOff() ); //ans Ende setzen
1312         if ( pHeader->GetLocalOff() != pHeader->GetGlobOff() )
1313             // Hat Sub-Ressourcen, deshalb extra freigeben
1314             PopContext();
1315     }
1316 
1317     return pHeader;
1318 }
1319 
1320 // ------------------------------------------------------------------
1321 
1322 sal_Int16 ResMgr::GetShort( void * pShort )
1323 {
1324     return ((*((sal_uInt8*)pShort + 0) << 8) |
1325             (*((sal_uInt8*)pShort + 1) << 0)   );
1326 }
1327 
1328 // ------------------------------------------------------------------
1329 
1330 sal_Int32 ResMgr::GetLong( void * pLong )
1331 {
1332     return ((*((sal_uInt8*)pLong + 0) << 24) |
1333             (*((sal_uInt8*)pLong + 1) << 16) |
1334             (*((sal_uInt8*)pLong + 2) <<  8) |
1335             (*((sal_uInt8*)pLong + 3) <<  0)   );
1336 }
1337 
1338 // ------------------------------------------------------------------
1339 
1340 sal_uInt64 ResMgr::GetUInt64( void* pDatum )
1341 {
1342     return ((sal_uInt64(*((sal_uInt8*)pDatum + 0)) << 56) |
1343             (sal_uInt64(*((sal_uInt8*)pDatum + 1)) << 48) |
1344             (sal_uInt64(*((sal_uInt8*)pDatum + 2)) << 40) |
1345             (sal_uInt64(*((sal_uInt8*)pDatum + 3)) << 32) |
1346             (sal_uInt64(*((sal_uInt8*)pDatum + 4)) << 24) |
1347             (sal_uInt64(*((sal_uInt8*)pDatum + 5)) << 16) |
1348             (sal_uInt64(*((sal_uInt8*)pDatum + 6)) <<  8) |
1349             (sal_uInt64(*((sal_uInt8*)pDatum + 7)) <<  0)   );
1350 }
1351 
1352 // -----------------------------------------------------------------------
1353 sal_uInt32 ResMgr::GetStringWithoutHook( UniString& rStr, const sal_uInt8* pStr )
1354 {
1355 	sal_uInt32 nLen=0;
1356     sal_uInt32 nRet = GetStringSize( pStr, nLen );
1357     UniString aString( (sal_Char*)pStr, RTL_TEXTENCODING_UTF8,
1358                        RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_MAPTOPRIVATE |
1359                        RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT |
1360                        RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT );
1361     rStr = aString;
1362     return nRet;
1363 }
1364 
1365 sal_uInt32 ResMgr::GetString( UniString& rStr, const sal_uInt8* pStr )
1366 {
1367     UniString aString;
1368     sal_uInt32 nRet =  GetStringWithoutHook( aString, pStr );
1369     if ( pImplResHookProc )
1370         pImplResHookProc( aString );
1371     rStr = aString;
1372     return nRet;
1373 }
1374 
1375 sal_uInt32 ResMgr::GetByteString( rtl::OString& rStr, const sal_uInt8* pStr )
1376 {
1377 	sal_uInt32 nLen=0;
1378     sal_uInt32 nRet = GetStringSize( pStr, nLen );
1379     rStr = rtl::OString( (const sal_Char*)pStr, nLen );
1380     return nRet;
1381 }
1382 
1383 // ------------------------------------------------------------------
1384 
1385 sal_uInt32 ResMgr::GetStringSize( const sal_uInt8* pStr, sal_uInt32& nLen )
1386 {
1387 	nLen = static_cast< sal_uInt32 >( strlen( (const char*)pStr ) );
1388     return GetStringSize( nLen );
1389 }
1390 
1391 // -----------------------------------------------------------------------
1392 
1393 sal_uInt32 ResMgr::GetRemainSize()
1394 {
1395     osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1396 
1397     if( pFallbackResMgr )
1398         return pFallbackResMgr->GetRemainSize();
1399 
1400     const ImpRCStack& rTop = aStack[nCurStack];
1401     return  (sal_uInt32)((long)(sal_uInt8 *)rTop.pResource +
1402                      rTop.pResource->GetLocalOff() -
1403                      (long)(sal_uInt8 *)rTop.pClassRes);
1404 }
1405 
1406 // -----------------------------------------------------------------------
1407 
1408 void* ResMgr::Increment( sal_uInt32 nSize )
1409 {
1410     osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1411 
1412     if( pFallbackResMgr )
1413         return pFallbackResMgr->Increment( nSize );
1414 
1415 	ImpRCStack& rStack = aStack[nCurStack];
1416     if( (rStack.Flags & RC_NOTFOUND) )
1417         return rStack.pClassRes;
1418 
1419     sal_uInt8* pClassRes = (sal_uInt8*)rStack.pClassRes + nSize;
1420 
1421     rStack.pClassRes = pClassRes;
1422 
1423     RSHEADER_TYPE* pRes = rStack.pResource;
1424 
1425 	sal_uInt32 nLocalOff = pRes->GetLocalOff();
1426     if ( (pRes->GetGlobOff() == nLocalOff) &&
1427          (((char*)pRes + nLocalOff) == rStack.pClassRes) &&
1428          (rStack.Flags & RC_AUTORELEASE))
1429     {
1430         PopContext( rStack.pResObj );
1431     }
1432 
1433     return pClassRes;
1434 }
1435 
1436 ResMgr* ResMgr::CreateFallbackResMgr( const ResId& rId, const Resource* pResource )
1437 {
1438     ResMgr *pFallback = NULL;
1439     if( nCurStack > 0 )
1440     {
1441         // get the next fallback level in resource file scope
1442         InternalResMgr* pRes = ResMgrContainer::get().getNextFallback( pImpRes );
1443         if( pRes )
1444         {
1445             // check that the fallback locale is not already in the chain of
1446             // fallbacks - prevent fallback loops
1447             ResMgr* pResMgr = this;
1448             while( pResMgr &&
1449                    ( pResMgr->pImpRes->aLocale.Language != pRes->aLocale.Language ||
1450                      pResMgr->pImpRes->aLocale.Country  != pRes->aLocale.Country  ||
1451                      pResMgr->pImpRes->aLocale.Variant  != pRes->aLocale.Variant )
1452                  )
1453             {
1454                 pResMgr = pResMgr->pOriginalResMgr;
1455             }
1456             if( pResMgr )
1457             {
1458                 // found a recursion, no fallback possible
1459                 ResMgrContainer::get().freeResMgr( pRes );
1460                 return NULL;
1461             }
1462             OSL_TRACE( "trying fallback: %s\n", OUStringToOString( pRes->aFileName, osl_getThreadTextEncoding() ).getStr() );
1463             pFallback = new ResMgr( pRes );
1464             pFallback->pOriginalResMgr = this;
1465             // try to recreate the resource stack
1466             bool bHaveStack = true;
1467             for( int i = 1; i < nCurStack; i++ )
1468             {
1469                 if( !aStack[i].pResource )
1470                 {
1471                     bHaveStack = false;
1472                     break;
1473                 }
1474                 ResId aId( aStack[i].pResource->GetId(), *pFallbackResMgr );
1475                 aId.SetRT( aStack[i].pResource->GetRT() );
1476                 if( !pFallback->GetResource( aId ) )
1477                 {
1478                     bHaveStack = false;
1479                     break;
1480                 }
1481             }
1482             if( bHaveStack )
1483             {
1484                 ResId aId( rId.GetId(), *pFallback );
1485                 aId.SetRT( rId.GetRT() );
1486                 if( !pFallback->GetResource( aId, pResource ) )
1487                     bHaveStack = false;
1488                 else
1489                     pFallback->aStack[pFallback->nCurStack].Flags |= RC_FALLBACK_UP;
1490             }
1491             if( !bHaveStack )
1492             {
1493                 delete pFallback;
1494                 pFallback = NULL;
1495             }
1496         }
1497     }
1498     return pFallback;
1499 }
1500 
1501 //---------------------------------------------------------------------------
1502 //
1503 // method left here for SDK compatibility,
1504 // used in "framework/source/services/substitutepathvars.cxx"
1505 //
1506 // phone numbers no longer in use for resource files
1507 //
1508 //---------------------------------------------------------------------------
1509 
1510 const char* ResMgr::GetLang( LanguageType& nType, sal_uInt16 nPrio )
1511 {
1512     if ( nType == LANGUAGE_SYSTEM || nType == LANGUAGE_DONTKNOW )
1513         nType = MsLangId::getSystemUILanguage();
1514 
1515     if ( nPrio == 0 )
1516     {
1517         switch ( nType )
1518         {
1519             case LANGUAGE_DANISH:
1520                 return "45";
1521 
1522             case LANGUAGE_DUTCH:
1523             case LANGUAGE_DUTCH_BELGIAN:
1524                 return "31";
1525 
1526             case LANGUAGE_ENGLISH:
1527             case LANGUAGE_ENGLISH_UK:
1528             case LANGUAGE_ENGLISH_EIRE:
1529             case LANGUAGE_ENGLISH_SAFRICA:
1530             case LANGUAGE_ENGLISH_JAMAICA:
1531             case LANGUAGE_ENGLISH_BELIZE:
1532             case LANGUAGE_ENGLISH_TRINIDAD:
1533             case LANGUAGE_ENGLISH_ZIMBABWE:
1534             case LANGUAGE_ENGLISH_PHILIPPINES:
1535                 return "44";
1536 
1537             case LANGUAGE_ENGLISH_US:
1538             case LANGUAGE_ENGLISH_CAN:
1539                 return "01";
1540 
1541             case LANGUAGE_ENGLISH_AUS:
1542             case LANGUAGE_ENGLISH_NZ:
1543                 return "61";
1544             case LANGUAGE_ESTONIAN:
1545                 return "77";
1546 
1547 
1548             case LANGUAGE_FINNISH:
1549                 return "35";
1550 
1551             case LANGUAGE_FRENCH_CANADIAN:
1552                 return "02";
1553 
1554             case LANGUAGE_FRENCH:
1555             case LANGUAGE_FRENCH_BELGIAN:
1556             case LANGUAGE_FRENCH_SWISS:
1557             case LANGUAGE_FRENCH_LUXEMBOURG:
1558             case LANGUAGE_FRENCH_MONACO:
1559                 return "33";
1560 
1561             case LANGUAGE_GERMAN:
1562             case LANGUAGE_GERMAN_SWISS:
1563             case LANGUAGE_GERMAN_AUSTRIAN:
1564             case LANGUAGE_GERMAN_LUXEMBOURG:
1565             case LANGUAGE_GERMAN_LIECHTENSTEIN:
1566                 return "49";
1567 
1568             case LANGUAGE_ITALIAN:
1569             case LANGUAGE_ITALIAN_SWISS:
1570                 return "39";
1571 
1572             case LANGUAGE_NORWEGIAN:
1573             case LANGUAGE_NORWEGIAN_BOKMAL:
1574                 return "47";
1575 
1576             case LANGUAGE_PORTUGUESE:
1577                 return "03";
1578 
1579             case LANGUAGE_PORTUGUESE_BRAZILIAN:
1580                 return "55";
1581 
1582             case LANGUAGE_SPANISH_DATED:
1583             case LANGUAGE_SPANISH_MEXICAN:
1584             case LANGUAGE_SPANISH_MODERN:
1585             case LANGUAGE_SPANISH_GUATEMALA:
1586             case LANGUAGE_SPANISH_COSTARICA:
1587             case LANGUAGE_SPANISH_PANAMA:
1588             case LANGUAGE_SPANISH_DOMINICAN_REPUBLIC:
1589             case LANGUAGE_SPANISH_VENEZUELA:
1590             case LANGUAGE_SPANISH_COLOMBIA:
1591             case LANGUAGE_SPANISH_PERU:
1592             case LANGUAGE_SPANISH_ARGENTINA:
1593             case LANGUAGE_SPANISH_ECUADOR:
1594             case LANGUAGE_SPANISH_CHILE:
1595             case LANGUAGE_SPANISH_URUGUAY:
1596             case LANGUAGE_SPANISH_PARAGUAY:
1597             case LANGUAGE_SPANISH_BOLIVIA:
1598                 return "34";
1599 
1600             case LANGUAGE_SWEDISH:
1601                 return "46";
1602 
1603             case LANGUAGE_POLISH:
1604                 return "48";
1605             case LANGUAGE_CZECH:
1606                 return "42";
1607             case LANGUAGE_SLOVENIAN:
1608                 return "50";
1609             case LANGUAGE_HUNGARIAN:
1610                 return "36";
1611             case LANGUAGE_RUSSIAN:
1612                 return "07";
1613             case LANGUAGE_SLOVAK:
1614                 return "43";
1615             case LANGUAGE_GREEK:
1616                 return "30";
1617             case LANGUAGE_TURKISH:
1618                 return "90";
1619 
1620             case LANGUAGE_CHINESE_SIMPLIFIED:
1621                 return "86";
1622             case LANGUAGE_CHINESE_TRADITIONAL:
1623                 return "88";
1624             case LANGUAGE_JAPANESE:
1625                 return "81";
1626             case LANGUAGE_KOREAN:
1627             case LANGUAGE_KOREAN_JOHAB:
1628                 return "82";
1629             case LANGUAGE_THAI:
1630 				return "66";
1631             case LANGUAGE_HINDI:
1632                 return "91";
1633 
1634             case LANGUAGE_ARABIC_PRIMARY_ONLY:
1635             case LANGUAGE_ARABIC_IRAQ:
1636             case LANGUAGE_ARABIC_EGYPT:
1637             case LANGUAGE_ARABIC_LIBYA:
1638             case LANGUAGE_ARABIC_ALGERIA:
1639             case LANGUAGE_ARABIC_MOROCCO:
1640             case LANGUAGE_ARABIC_TUNISIA:
1641             case LANGUAGE_ARABIC_OMAN:
1642             case LANGUAGE_ARABIC_YEMEN:
1643             case LANGUAGE_ARABIC_SYRIA:
1644             case LANGUAGE_ARABIC_JORDAN:
1645             case LANGUAGE_ARABIC_LEBANON:
1646             case LANGUAGE_ARABIC_KUWAIT:
1647             case LANGUAGE_ARABIC_UAE:
1648             case LANGUAGE_ARABIC_BAHRAIN:
1649             case LANGUAGE_ARABIC_QATAR:
1650                 return "96";
1651 
1652             case LANGUAGE_HEBREW:
1653                 return "97";
1654 
1655             case LANGUAGE_CATALAN:
1656                 return "37";
1657 
1658             default:
1659                 return "99";
1660         }
1661     }
1662     else if ( nPrio == 1 )
1663     {
1664         switch ( nType )
1665         {
1666             case LANGUAGE_FRENCH_CANADIAN:
1667                 return "33";
1668 
1669             case LANGUAGE_PORTUGUESE_BRAZILIAN:
1670                 return "03";
1671 
1672             default:
1673                 return NULL;
1674         }
1675     }
1676     else if ( nPrio == 2 )
1677         return "01";
1678     else if ( nPrio == 3 )
1679         return "44";
1680     else if ( nPrio == 4 )
1681         return "49";
1682     else
1683         return "99";
1684 }
1685 
1686 // -----------------------------------------------------------------------
1687 
1688 ResMgr* ResMgr::CreateResMgr( const sal_Char* pPrefixName,
1689                               com::sun::star::lang::Locale aLocale )
1690 {
1691     osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1692 
1693     OUString aPrefix( pPrefixName, strlen( pPrefixName ), osl_getThreadTextEncoding() );
1694 
1695     if( ! aLocale.Language.getLength() )
1696         aLocale = ResMgrContainer::get().getDefLocale();
1697 
1698     InternalResMgr* pImp = ResMgrContainer::get().getResMgr( aPrefix, aLocale );
1699     return pImp ? new ResMgr( pImp ) : NULL;
1700 }
1701 
1702 // -----------------------------------------------------------------------
1703 
1704 ResMgr* ResMgr::SearchCreateResMgr(
1705     const sal_Char* pPrefixName,
1706     com::sun::star::lang::Locale& rLocale )
1707 {
1708     osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1709 
1710     OUString aPrefix( pPrefixName, strlen( pPrefixName ), osl_getThreadTextEncoding() );
1711 
1712     if( ! rLocale.Language.getLength() )
1713         rLocale = ResMgrContainer::get().getDefLocale();
1714 
1715     InternalResMgr* pImp = ResMgrContainer::get().getResMgr( aPrefix, rLocale );
1716     return pImp ? new ResMgr( pImp ) : NULL;
1717 }
1718 
1719 // -----------------------------------------------------------------------
1720 
1721 sal_Int16 ResMgr::ReadShort()
1722 {
1723     osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1724 
1725     if( pFallbackResMgr )
1726         return pFallbackResMgr->ReadShort();
1727 
1728     sal_Int16 n = GetShort( GetClass() );
1729     Increment( sizeof( sal_Int16 ) );
1730     return n;
1731 }
1732 
1733 // -----------------------------------------------------------------------
1734 
1735 sal_Int32 ResMgr::ReadLong()
1736 {
1737     osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1738 
1739     if( pFallbackResMgr )
1740         return pFallbackResMgr->ReadLong();
1741 
1742     sal_Int32 n = GetLong( GetClass() );
1743     Increment( sizeof( sal_Int32 ) );
1744     return n;
1745 }
1746 
1747 // -----------------------------------------------------------------------
1748 
1749 UniString ResMgr::ReadStringWithoutHook()
1750 {
1751     osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1752 
1753     if( pFallbackResMgr )
1754         return pFallbackResMgr->ReadStringWithoutHook();
1755 
1756     UniString aRet;
1757 
1758     const ImpRCStack& rTop = aStack[nCurStack];
1759     if( (rTop.Flags & RC_NOTFOUND) )
1760     {
1761         #if OSL_DEBUG_LEVEL > 0
1762         aRet = OUString( RTL_CONSTASCII_USTRINGPARAM( "<resource not found>" ) );
1763         #endif
1764     }
1765     else
1766         Increment( GetStringWithoutHook( aRet, (const sal_uInt8*)GetClass() ) );
1767 
1768     return aRet;
1769 }
1770 
1771 UniString ResMgr::ReadString()
1772 {
1773     UniString aRet = ReadStringWithoutHook();
1774     if ( pImplResHookProc )
1775         pImplResHookProc( aRet );
1776     return aRet;
1777 }
1778 
1779 rtl::OString ResMgr::ReadByteString()
1780 {
1781     osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1782 
1783     if( pFallbackResMgr )
1784         return pFallbackResMgr->ReadByteString();
1785 
1786     rtl::OString aRet;
1787 
1788     const ImpRCStack& rTop = aStack[nCurStack];
1789     if( (rTop.Flags & RC_NOTFOUND) )
1790     {
1791         #if OSL_DEBUG_LEVEL > 0
1792         aRet = OString( "<resource not found>" );
1793         #endif
1794     }
1795     else
1796         Increment( GetByteString( aRet, (const sal_uInt8*)GetClass() ) );
1797 
1798     return aRet;
1799 }
1800 
1801 // -----------------------------------------------------------------------
1802 
1803 rtl::OString ResMgr::GetAutoHelpId()
1804 {
1805     osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1806 
1807     if( pFallbackResMgr )
1808         return pFallbackResMgr->GetAutoHelpId();
1809 
1810     OSL_ENSURE( nCurStack, "resource stack empty in Auto help id generation" );
1811     if( nCurStack < 1 || nCurStack > 2 )
1812         return rtl::OString();
1813 
1814     // prepare HID, start with resource prefix
1815     rtl::OStringBuffer aHID( 32 );
1816     aHID.append( rtl::OUStringToOString( pImpRes->aPrefix, RTL_TEXTENCODING_UTF8 ) );
1817     aHID.append( '.' );
1818 
1819     // append type
1820     const ImpRCStack *pRC = StackTop();
1821     OSL_ENSURE( pRC, "missing resource stack level" );
1822 
1823     if ( nCurStack == 1 )
1824     {
1825         // auto help ids for top level windows
1826         switch( pRC->pResource->GetRT() ) {
1827             case RSC_DOCKINGWINDOW:		aHID.append( "DockingWindow" );    break;
1828             case RSC_WORKWIN:           aHID.append( "WorkWindow" );       break;
1829             case RSC_MODELESSDIALOG:    aHID.append( "ModelessDialog" );   break;
1830             case RSC_FLOATINGWINDOW:    aHID.append( "FloatingWindow" );   break;
1831             case RSC_MODALDIALOG:       aHID.append( "ModalDialog" );      break;
1832             case RSC_TABPAGE:           aHID.append( "TabPage" );          break;
1833             default: return rtl::OString();
1834         }
1835     }
1836     else
1837     {
1838         // only controls with the following parents get auto help ids
1839         const ImpRCStack *pRC1 = StackTop(1);
1840         switch( pRC1->pResource->GetRT() ) {
1841             case RSC_DOCKINGWINDOW:
1842             case RSC_WORKWIN:
1843             case RSC_MODELESSDIALOG:
1844             case RSC_FLOATINGWINDOW:
1845             case RSC_MODALDIALOG:
1846             case RSC_TABPAGE:
1847                 // intentionally no breaks!
1848                 // auto help ids for controls
1849                 switch( pRC->pResource->GetRT() ) {
1850 		            case RSC_TABCONTROL:        aHID.append( "TabControl" );       break;
1851                     case RSC_RADIOBUTTON:       aHID.append( "RadioButton" );      break;
1852                     case RSC_CHECKBOX:          aHID.append( "CheckBox" );         break;
1853                     case RSC_TRISTATEBOX:       aHID.append( "TriStateBox" );      break;
1854                     case RSC_EDIT:              aHID.append( "Edit" );             break;
1855                     case RSC_MULTILINEEDIT:     aHID.append( "MultiLineEdit" );    break;
1856                     case RSC_MULTILISTBOX:      aHID.append( "MultiListBox" );     break;
1857                     case RSC_LISTBOX:           aHID.append( "ListBox" );          break;
1858                     case RSC_COMBOBOX:          aHID.append( "ComboBox" );         break;
1859                     case RSC_PUSHBUTTON:        aHID.append( "PushButton" );       break;
1860                     case RSC_SPINFIELD:         aHID.append( "SpinField" );        break;
1861                     case RSC_PATTERNFIELD:      aHID.append( "PatternField" );     break;
1862                     case RSC_NUMERICFIELD:      aHID.append( "NumericField" );     break;
1863                     case RSC_METRICFIELD:       aHID.append( "MetricField" );      break;
1864                     case RSC_CURRENCYFIELD:     aHID.append( "CurrencyField" );    break;
1865                     case RSC_DATEFIELD:         aHID.append( "DateField" );        break;
1866                     case RSC_TIMEFIELD:         aHID.append( "TimeField" );        break;
1867                     case RSC_IMAGERADIOBUTTON:  aHID.append( "ImageRadioButton" ); break;
1868                     case RSC_NUMERICBOX:        aHID.append( "NumericBox" );       break;
1869                     case RSC_METRICBOX:         aHID.append( "MetricBox" );        break;
1870                     case RSC_CURRENCYBOX:       aHID.append( "CurrencyBox" );      break;
1871                     case RSC_DATEBOX:           aHID.append( "DateBox" );          break;
1872                     case RSC_TIMEBOX:           aHID.append( "TimeBox" );          break;
1873                     case RSC_IMAGEBUTTON:       aHID.append( "ImageButton" );      break;
1874                     case RSC_MENUBUTTON:        aHID.append( "MenuButton" );       break;
1875                     case RSC_MOREBUTTON:        aHID.append( "MoreButton" );       break;
1876                     default:
1877                         // no type, no auto HID
1878                         return rtl::OString();
1879                 }
1880                 break;
1881             default:
1882                 return rtl::OString();
1883         }
1884     }
1885 
1886     // append resource id hierarchy
1887     for( int nOff = nCurStack-1; nOff >= 0; nOff-- )
1888     {
1889         aHID.append( '.' );
1890         pRC = StackTop( nOff );
1891 
1892         OSL_ENSURE( pRC->pResource, "missing resource in resource stack level !" );
1893         if( pRC->pResource )
1894             aHID.append( sal_Int32( pRC->pResource->GetId() ) );
1895     }
1896 
1897     return aHID.makeStringAndClear();
1898 }
1899 
1900 // -----------------------------------------------------------------------
1901 
1902 void ResMgr::SetReadStringHook( ResHookProc pProc )
1903 {
1904     osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1905     pImplResHookProc = pProc;
1906 }
1907 
1908 // -----------------------------------------------------------------------
1909 
1910 ResHookProc ResMgr::GetReadStringHook()
1911 {
1912     return pImplResHookProc;
1913 }
1914 
1915 // -----------------------------------------------------------------------
1916 
1917 void ResMgr::SetDefaultLocale( const com::sun::star::lang::Locale& rLocale )
1918 {
1919     osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1920     ResMgrContainer::get().setDefLocale( rLocale );
1921 }
1922 
1923 // -----------------------------------------------------------------------
1924 
1925 const OUString& ResMgr::GetFileName() const
1926 {
1927     return pImpRes->aFileName;
1928 }
1929 
1930 // =======================================================================
1931 
1932 SimpleResMgr::SimpleResMgr( const sal_Char* pPrefixName,
1933                             const ::com::sun::star::lang::Locale& rLocale )
1934 {
1935     OUString aPrefix( pPrefixName, strlen( pPrefixName ), osl_getThreadTextEncoding() );
1936     com::sun::star::lang::Locale aLocale( rLocale );
1937 
1938     osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1939     if( ! aLocale.Language.getLength() )
1940         aLocale = ResMgrContainer::get().getDefLocale();
1941 
1942     m_pResImpl = ResMgrContainer::get().getResMgr( aPrefix, aLocale, true );
1943     DBG_ASSERT( m_pResImpl, "SimpleResMgr::SimpleResMgr : have no impl class !" );
1944 }
1945 
1946 // -----------------------------------------------------------------------
1947 SimpleResMgr::SimpleResMgr( const ::rtl::OUString& _rPrefixName, ::com::sun::star::lang::Locale& _inout_Locale )
1948 {
1949     osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1950     m_pResImpl = ResMgrContainer::get().getResMgr( _rPrefixName, _inout_Locale, true );
1951 }
1952 
1953 // -----------------------------------------------------------------------
1954 SimpleResMgr::~SimpleResMgr()
1955 {
1956     delete m_pResImpl;
1957 }
1958 
1959 // -----------------------------------------------------------------------
1960 SimpleResMgr* SimpleResMgr::Create( const sal_Char* pPrefixName, com::sun::star::lang::Locale aLocale )
1961 {
1962     return new SimpleResMgr( pPrefixName, aLocale );
1963 }
1964 
1965 // -----------------------------------------------------------------------
1966 bool SimpleResMgr::IsAvailable( RESOURCE_TYPE _resourceType, sal_uInt32 _resourceId )
1967 {
1968     vos::OGuard aGuard(m_aAccessSafety);
1969 
1970     if ( ( RSC_STRING != _resourceType ) && ( RSC_RESOURCE != _resourceType ) )
1971         return false;
1972 
1973     DBG_ASSERT( m_pResImpl, "SimpleResMgr::IsAvailable: have no impl class !" );
1974     return m_pResImpl->IsGlobalAvailable( _resourceType, _resourceId );
1975 }
1976 
1977 // -----------------------------------------------------------------------
1978 UniString SimpleResMgr::ReadString( sal_uInt32 nId )
1979 {
1980     vos::OGuard aGuard(m_aAccessSafety);
1981 
1982     DBG_ASSERT( m_pResImpl, "SimpleResMgr::ReadString : have no impl class !" );
1983     // perhaps constructed with an invalid filename ?
1984 
1985     UniString sReturn;
1986     if ( !m_pResImpl )
1987         return sReturn;
1988 
1989     void* pResHandle = NULL;
1990     InternalResMgr* pFallback = m_pResImpl;
1991     RSHEADER_TYPE* pResHeader = (RSHEADER_TYPE*)m_pResImpl->LoadGlobalRes( RSC_STRING, nId, &pResHandle );
1992     if ( !pResHeader )
1993     {
1994         osl::Guard<osl::Mutex> aGuard2( getResMgrMutex() );
1995 
1996         // try fallback
1997         while( ! pResHandle && pFallback )
1998         {
1999             InternalResMgr* pOldFallback = pFallback;
2000             pFallback = ResMgrContainer::get().getNextFallback( pFallback );
2001             if( pOldFallback != m_pResImpl )
2002                 ResMgrContainer::get().freeResMgr( pOldFallback );
2003             if( pFallback )
2004             {
2005                 // handle possible recursion
2006                 if( pFallback->aLocale.Language != m_pResImpl->aLocale.Language ||
2007                     pFallback->aLocale.Country  != m_pResImpl->aLocale.Country  ||
2008                     pFallback->aLocale.Variant  != m_pResImpl->aLocale.Variant )
2009                 {
2010                     pResHeader = (RSHEADER_TYPE*)pFallback->LoadGlobalRes( RSC_STRING, nId, &pResHandle );
2011                 }
2012                 else
2013                 {
2014                     ResMgrContainer::get().freeResMgr( pFallback );
2015                     pFallback = NULL;
2016                 }
2017             }
2018         }
2019         if( ! pResHandle )
2020             // no such resource
2021             return sReturn;
2022     }
2023 
2024     // sal_uIntPtr nLen = pResHeader->GetLocalOff() - sizeof(RSHEADER_TYPE);
2025     ResMgr::GetString( sReturn, (const sal_uInt8*)(pResHeader+1) );
2026 
2027     // not neccessary with te current implementation which holds the string table permanently, but to be sure ....
2028     // note: pFallback cannot be NULL here and is either the fallback or m_pResImpl
2029     pFallback->FreeGlobalRes( pResHeader, pResHandle );
2030     if( m_pResImpl != pFallback )
2031     {
2032         osl::Guard<osl::Mutex> aGuard2( getResMgrMutex() );
2033 
2034         ResMgrContainer::get().freeResMgr( pFallback );
2035     }
2036     return sReturn;
2037 }
2038 
2039 // -----------------------------------------------------------------------
2040 
2041 const ::com::sun::star::lang::Locale& SimpleResMgr::GetLocale() const
2042 {
2043     DBG_ASSERT( IsValid(), "SimpleResMgr::ReadBlob: invalid, this will crash!" );
2044     return m_pResImpl->aLocale;
2045 }
2046 
2047 // -----------------------------------------------------------------------
2048 
2049 sal_uInt32 SimpleResMgr::ReadBlob( sal_uInt32 nId, void** pBuffer )
2050 {
2051     vos::OGuard aGuard(m_aAccessSafety);
2052 
2053     DBG_ASSERT( m_pResImpl, "SimpleResMgr::ReadBlob : have no impl class !" );
2054 
2055     // perhaps constructed with an invalid filename ?
2056     DBG_ASSERT( pBuffer, "SimpleResMgr::ReadBlob : invalid argument !" );
2057     *pBuffer = NULL;
2058 
2059     void* pResHandle = NULL;
2060     InternalResMgr* pFallback = m_pResImpl;
2061     RSHEADER_TYPE* pResHeader = (RSHEADER_TYPE*)m_pResImpl->LoadGlobalRes( RSC_RESOURCE, nId, &pResHandle );
2062     DBG_ASSERT( pResHeader, "SimpleResMgr::ReadBlob : couldn't find the resource with the given id !" );
2063 
2064     if ( !pResHeader )
2065     {
2066         osl::Guard<osl::Mutex> aGuard2( getResMgrMutex() );
2067 
2068         // try fallback
2069         while( ! pResHandle && pFallback )
2070         {
2071             InternalResMgr* pOldFallback = pFallback;
2072             pFallback = ResMgrContainer::get().getNextFallback( pFallback );
2073             if( pOldFallback != m_pResImpl )
2074                 ResMgrContainer::get().freeResMgr( pOldFallback );
2075             if( pFallback )
2076             {
2077                 // handle possible recursion
2078                 if( pFallback->aLocale.Language != m_pResImpl->aLocale.Language ||
2079                     pFallback->aLocale.Country  != m_pResImpl->aLocale.Country  ||
2080                     pFallback->aLocale.Variant  != m_pResImpl->aLocale.Variant )
2081                 {
2082                     pResHeader = (RSHEADER_TYPE*)pFallback->LoadGlobalRes( RSC_RESOURCE, nId, &pResHandle );
2083                 }
2084                 else
2085                 {
2086                     ResMgrContainer::get().freeResMgr( pFallback );
2087                     pFallback = NULL;
2088                 }
2089             }
2090         }
2091         if( ! pResHandle )
2092             // no exception handling, this would require the locking of the solar mutex which isn't allowed within this class
2093             return 0;
2094     }
2095 
2096     DBG_ASSERT( pResHandle == NULL, "SimpleResMgr::ReadBlob : behaviour of LoadGlobalRes changed !" );
2097     // if pResHandle is not NULL the FreeBlob wouldn't have to delete the pointer given as pBuffer, but
2098     // FreeBlob doesn't know that so it would probably crash ....
2099 
2100     sal_uInt32 nRemaining = pResHeader->GetLocalOff() - sizeof(RSHEADER_TYPE);
2101     *pBuffer = (void*)(((sal_uInt8*)pResHeader) + sizeof(RSHEADER_TYPE));
2102 
2103     // free an eventual fallback InternalResMgr
2104     if( m_pResImpl != pFallback )
2105     {
2106         osl::Guard<osl::Mutex> aGuard2( getResMgrMutex() );
2107 
2108         ResMgrContainer::get().freeResMgr( pFallback );
2109     }
2110 
2111     return nRemaining;
2112 }
2113 
2114 // -----------------------------------------------------------------------
2115 
2116 void SimpleResMgr::FreeBlob( void* pBuffer )
2117 {
2118     void* pCompleteBuffer = (void*)(((sal_uInt8*)pBuffer) - sizeof(RSHEADER_TYPE));
2119     rtl_freeMemory(pCompleteBuffer);
2120 }
2121