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