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