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