Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <config_folders.h>
21 :
22 : #include "sal/config.h"
23 :
24 : #include <cassert>
25 :
26 : #include <string.h>
27 : #include <stdio.h>
28 : #include <stdlib.h>
29 :
30 : #include <tools/debug.hxx>
31 : #include <tools/stream.hxx>
32 : #include <tools/resmgr.hxx>
33 : #include <tools/rc.hxx>
34 : #include <tools/rcid.h>
35 : #include <osl/endian.h>
36 : #include <osl/process.h>
37 : #include <osl/thread.h>
38 : #include <osl/file.hxx>
39 : #include <osl/mutex.hxx>
40 : #include <osl/signal.h>
41 : #include <rtl/ustrbuf.hxx>
42 : #include <rtl/strbuf.hxx>
43 : #include <sal/log.hxx>
44 : #include <rtl/instance.hxx>
45 : #include <rtl/bootstrap.hxx>
46 : #include <i18nlangtag/languagetag.hxx>
47 : #include <i18nlangtag/mslangid.hxx>
48 : #include <tools/simplerm.hxx>
49 :
50 : #include <functional>
51 : #include <algorithm>
52 : #include <boost/unordered_map.hpp>
53 : #include <list>
54 : #include <set>
55 :
56 :
57 : using namespace osl;
58 :
59 : // for thread safety
60 : static osl::Mutex* pResMgrMutex = NULL;
61 :
62 1 : static osl::Mutex& getResMgrMutex()
63 : {
64 1 : if( !pResMgrMutex )
65 : {
66 1 : osl::Guard<osl::Mutex> aGuard( *osl::Mutex::getGlobalMutex() );
67 1 : if( ! pResMgrMutex )
68 1 : pResMgrMutex = new osl::Mutex();
69 : }
70 1 : return *pResMgrMutex;
71 : }
72 :
73 : struct ImpContent;
74 :
75 : class InternalResMgr
76 : {
77 : friend class ResMgr;
78 : friend class SimpleResMgr;
79 : friend class ResMgrContainer;
80 :
81 : ImpContent * pContent;
82 : sal_uInt32 nOffCorrection;
83 : sal_uInt8 * pStringBlock;
84 : SvStream * pStm;
85 : bool bEqual2Content;
86 : sal_uInt32 nEntries;
87 : OUString aFileName;
88 : OUString aPrefix;
89 : OUString aResName;
90 : bool bSingular;
91 : LanguageTag aLocale;
92 : boost::unordered_map<sal_uInt64, int>* pResUseDump;
93 :
94 : InternalResMgr( const OUString& rFileURL,
95 : const OUString& aPrefix,
96 : const OUString& aResName,
97 : const LanguageTag& rLocale );
98 : ~InternalResMgr();
99 : bool Create();
100 :
101 : bool IsGlobalAvailable( RESOURCE_TYPE nRT, sal_uInt32 nId ) const;
102 : void * LoadGlobalRes( RESOURCE_TYPE nRT, sal_uInt32 nId,
103 : void **pResHandle );
104 : public:
105 : static void FreeGlobalRes( void *, void * );
106 : };
107 :
108 : class ResMgrContainer
109 : {
110 : static ResMgrContainer* pOneInstance;
111 :
112 0 : struct ContainerElement
113 : {
114 : InternalResMgr* pResMgr;
115 : OUString aFileURL;
116 : int nRefCount;
117 : int nLoadCount;
118 :
119 0 : ContainerElement() :
120 : pResMgr( NULL ),
121 : nRefCount( 0 ),
122 0 : nLoadCount( 0 )
123 0 : {}
124 : };
125 :
126 : boost::unordered_map< OUString, ContainerElement, OUStringHash> m_aResFiles;
127 : LanguageTag m_aDefLocale;
128 :
129 0 : ResMgrContainer() : m_aDefLocale( LANGUAGE_SYSTEM) { init(); }
130 : ~ResMgrContainer();
131 :
132 : void init();
133 :
134 : public:
135 : static ResMgrContainer& get();
136 : static void release();
137 :
138 : InternalResMgr* getResMgr( const OUString& rPrefix,
139 : LanguageTag& rLocale,
140 : bool bForceNewInstance = false
141 : );
142 : InternalResMgr* getNextFallback( InternalResMgr* pResMgr );
143 :
144 : void freeResMgr( InternalResMgr* pResMgr );
145 :
146 0 : void setDefLocale( const LanguageTag& rLocale )
147 0 : { m_aDefLocale = rLocale; }
148 0 : const LanguageTag& getDefLocale() const
149 0 : { return m_aDefLocale; }
150 : };
151 :
152 : ResMgrContainer* ResMgrContainer::pOneInstance = NULL;
153 :
154 0 : ResMgrContainer& ResMgrContainer::get()
155 : {
156 0 : if( ! pOneInstance )
157 0 : pOneInstance = new ResMgrContainer();
158 0 : return *pOneInstance;
159 : }
160 :
161 0 : ResMgrContainer::~ResMgrContainer()
162 : {
163 0 : for( boost::unordered_map< OUString, ContainerElement, OUStringHash >::iterator it =
164 0 : m_aResFiles.begin(); it != m_aResFiles.end(); ++it )
165 : {
166 : OSL_TRACE( "Resource file %s loaded %d times",
167 : OUStringToOString( it->second.aFileURL, osl_getThreadTextEncoding() ).getStr(),
168 : it->second.nLoadCount );
169 0 : delete it->second.pResMgr;
170 : }
171 0 : }
172 :
173 1 : void ResMgrContainer::release()
174 : {
175 1 : delete pOneInstance;
176 1 : pOneInstance = NULL;
177 1 : }
178 :
179 0 : void ResMgrContainer::init()
180 : {
181 : assert( m_aResFiles.empty() );
182 :
183 : // get resource path
184 0 : OUString uri("$BRAND_BASE_DIR/" LIBO_SHARE_RESOURCE_FOLDER "/");
185 0 : rtl::Bootstrap::expandMacros(uri); //TODO: detect failure
186 :
187 : // collect all possible resource files
188 0 : Directory aDir( uri );
189 0 : if( aDir.open() == FileBase::E_None )
190 : {
191 0 : DirectoryItem aItem;
192 0 : while( aDir.getNextItem( aItem ) == FileBase::E_None )
193 : {
194 0 : FileStatus aStatus(osl_FileStatus_Mask_FileName);
195 0 : if( aItem.getFileStatus( aStatus ) == FileBase::E_None )
196 : {
197 0 : OUString aFileName = aStatus.getFileName();
198 0 : if( ! aFileName.endsWithIgnoreAsciiCase( ".res" ) )
199 0 : continue;
200 0 : OUString aResName = aFileName.copy( 0, aFileName.getLength() - strlen(".res") );
201 0 : if( aResName.isEmpty() )
202 0 : continue;
203 : assert( m_aResFiles.find( aResName ) == m_aResFiles.end() );
204 0 : m_aResFiles[ aResName ].aFileURL = uri + aFileName;
205 : SAL_INFO(
206 : "tools.rc",
207 : "ResMgrContainer: " << aResName << " -> "
208 0 : << m_aResFiles[ aResName ].aFileURL );
209 : }
210 0 : }
211 : }
212 : else
213 : SAL_WARN( "tools.rc", "opening dir " << uri << " failed" );
214 :
215 : // set default language
216 0 : LanguageType nLang = MsLangId::getSystemUILanguage();
217 0 : m_aDefLocale.reset( nLang);
218 0 : }
219 :
220 : namespace
221 : {
222 0 : bool isAlreadyPureenUS(const LanguageTag &rLocale)
223 : {
224 0 : return ( rLocale.getLanguageType() == LANGUAGE_ENGLISH_US );
225 : }
226 : }
227 :
228 0 : InternalResMgr* ResMgrContainer::getResMgr( const OUString& rPrefix,
229 : LanguageTag& rLocale,
230 : bool bForceNewInstance
231 : )
232 : {
233 0 : LanguageTag aLocale( rLocale );
234 0 : boost::unordered_map< OUString, ContainerElement, OUStringHash >::iterator it = m_aResFiles.end();
235 :
236 0 : ::std::vector< OUString > aFallbacks( aLocale.getFallbackStrings( true));
237 0 : if (!isAlreadyPureenUS( aLocale))
238 0 : aFallbacks.push_back( "en-US"); // last resort if all fallbacks fail
239 :
240 0 : for (::std::vector< OUString >::const_iterator fb( aFallbacks.begin()); fb != aFallbacks.end(); ++fb)
241 : {
242 0 : OUString aSearch( rPrefix + *fb );
243 0 : it = m_aResFiles.find( aSearch );
244 0 : if( it != m_aResFiles.end() )
245 : {
246 : // ensure InternalResMgr existance
247 0 : if( ! it->second.pResMgr )
248 : {
249 : InternalResMgr* pImp =
250 0 : new InternalResMgr( it->second.aFileURL, rPrefix, it->first, aLocale );
251 0 : if( ! pImp->Create() )
252 : {
253 0 : delete pImp;
254 0 : continue;
255 : }
256 0 : it->second.pResMgr = pImp;
257 : }
258 0 : break;
259 : }
260 0 : }
261 : // try if there is anything with this prefix at all
262 0 : if( it == m_aResFiles.end() )
263 : {
264 0 : aLocale.reset( LANGUAGE_SYSTEM);
265 0 : it = m_aResFiles.find( rPrefix );
266 0 : if( it == m_aResFiles.end() )
267 : {
268 0 : for( it = m_aResFiles.begin(); it != m_aResFiles.end(); ++it )
269 : {
270 0 : if( it->first.matchIgnoreAsciiCase( rPrefix ) )
271 : {
272 : // ensure InternalResMgr existance
273 0 : if( ! it->second.pResMgr )
274 : {
275 : InternalResMgr* pImp =
276 0 : new InternalResMgr( it->second.aFileURL,
277 : rPrefix,
278 0 : it->first,
279 0 : aLocale );
280 0 : if( ! pImp->Create() )
281 : {
282 0 : delete pImp;
283 0 : continue;
284 : }
285 0 : it->second.pResMgr = pImp;
286 : }
287 : // try to guess locale
288 0 : sal_Int32 nIndex = rPrefix.getLength();
289 0 : if (nIndex < it->first.getLength())
290 0 : aLocale.reset( it->first.copy( nIndex));
291 : else
292 : {
293 : SAL_WARN( "tools.rc", "ResMgrContainer::getResMgr: it->first " <<
294 : it->first << " shorter than prefix " << rPrefix);
295 : }
296 0 : break;
297 : }
298 : }
299 : }
300 : }
301 : // give up
302 0 : if( it == m_aResFiles.end() )
303 : {
304 0 : OUString sURL = rPrefix + rLocale.getBcp47() + ".res";
305 0 : if ( m_aResFiles.find(sURL) == m_aResFiles.end() )
306 : {
307 0 : m_aResFiles[ sURL ].aFileURL = sURL;
308 0 : return getResMgr(rPrefix,rLocale,bForceNewInstance);
309 : } // if ( m_aResFiles.find(sURL) == m_aResFiles.end() )
310 0 : return NULL;
311 : }
312 :
313 0 : rLocale = aLocale;
314 : // at this point it->second.pResMgr must be filled either by creating a new one
315 : // (then the refcount is still 0) or because we already had one
316 0 : InternalResMgr* pImp = it->second.pResMgr;
317 :
318 0 : if( it->second.nRefCount == 0 )
319 0 : it->second.nLoadCount++;
320 :
321 : // for SimpleResMgr
322 0 : if( bForceNewInstance )
323 : {
324 0 : if( it->second.nRefCount == 0 )
325 : {
326 : // shortcut: the match algorithm already created the InternalResMgr
327 : // take it instead of creating yet another one
328 0 : it->second.pResMgr = NULL;
329 0 : pImp->bSingular = true;
330 : }
331 : else
332 : {
333 0 : pImp = new InternalResMgr( it->second.aFileURL, rPrefix, it->first, aLocale );
334 0 : pImp->bSingular = true;
335 0 : if( !pImp->Create() )
336 : {
337 0 : delete pImp;
338 0 : pImp = NULL;
339 : }
340 : else
341 0 : it->second.nLoadCount++;
342 : }
343 : }
344 : else
345 0 : it->second.nRefCount++;
346 :
347 0 : return pImp;
348 : }
349 :
350 0 : InternalResMgr* ResMgrContainer::getNextFallback( InternalResMgr* pMgr )
351 : {
352 : /* TODO-BCP47: this is nasty, but the previous code simply stripped a
353 : * locale's variant and country in subsequent calls to end up with language
354 : * only and then fallback to en-US if all failed, so this is at least
355 : * equivalent if not better. Maybe this method could be changed to get
356 : * passed / remember a fallback list and an index within to pick the next.
357 : * */
358 :
359 0 : ::std::vector< OUString > aFallbacks( pMgr->aLocale.getFallbackStrings( true));
360 : // The first is the locale itself, use next fallback or en-US.
361 : /* TODO: what happens if the chain is "en-US", "en" -> "en-US", ...
362 : * This was already an issue with the previous code. */
363 0 : LanguageTag aLocale( ((aFallbacks.size() > 1) ? aFallbacks[1] : OUString( "en-US")));
364 0 : InternalResMgr* pNext = getResMgr( pMgr->aPrefix, aLocale, pMgr->bSingular );
365 : // prevent recursion
366 0 : if( pNext == pMgr || ( pNext && pNext->aResName.equals( pMgr->aResName ) ) )
367 : {
368 0 : if( pNext->bSingular )
369 0 : delete pNext;
370 0 : pNext = NULL;
371 : }
372 0 : return pNext;
373 : }
374 :
375 0 : void ResMgrContainer::freeResMgr( InternalResMgr* pResMgr )
376 : {
377 0 : if( pResMgr->bSingular )
378 0 : delete pResMgr;
379 : else
380 : {
381 : boost::unordered_map< OUString, ContainerElement, OUStringHash >::iterator it =
382 0 : m_aResFiles.find( pResMgr->aResName );
383 0 : if( it != m_aResFiles.end() )
384 : {
385 : DBG_ASSERT( it->second.nRefCount > 0, "InternalResMgr freed too often" );
386 0 : if( it->second.nRefCount > 0 )
387 0 : it->second.nRefCount--;
388 0 : if( it->second.nRefCount == 0 )
389 : {
390 0 : delete it->second.pResMgr;
391 0 : it->second.pResMgr = NULL;
392 : }
393 : }
394 : }
395 0 : }
396 :
397 : #ifdef DBG_UTIL
398 : void Resource::TestRes()
399 : {
400 : if( m_pResMgr )
401 : m_pResMgr->TestStack( this );
402 : }
403 : #endif
404 :
405 : struct ImpContent
406 : {
407 : sal_uInt64 nTypeAndId;
408 : sal_uInt32 nOffset;
409 : };
410 :
411 : struct ImpContentLessCompare : public ::std::binary_function< ImpContent, ImpContent, bool>
412 : {
413 0 : inline bool operator() (const ImpContent& lhs, const ImpContent& rhs) const
414 : {
415 0 : return lhs.nTypeAndId < rhs.nTypeAndId;
416 : }
417 : };
418 :
419 : static ResHookProc pImplResHookProc = 0;
420 :
421 0 : InternalResMgr::InternalResMgr( const OUString& rFileURL,
422 : const OUString& rPrefix,
423 : const OUString& rResName,
424 : const LanguageTag& rLocale )
425 : : pContent( NULL )
426 : , nOffCorrection( 0 )
427 : , pStringBlock( NULL )
428 : , pStm( NULL )
429 : , bEqual2Content( true )
430 : , nEntries( 0 )
431 : , aFileName( rFileURL )
432 : , aPrefix( rPrefix )
433 : , aResName( rResName )
434 : , bSingular( false )
435 : , aLocale( rLocale )
436 0 : , pResUseDump( 0 )
437 : {
438 0 : }
439 :
440 0 : InternalResMgr::~InternalResMgr()
441 : {
442 0 : rtl_freeMemory(pContent);
443 0 : rtl_freeMemory(pStringBlock);
444 0 : delete pStm;
445 :
446 : #ifdef DBG_UTIL
447 : if( pResUseDump )
448 : {
449 : const sal_Char* pLogFile = getenv( "STAR_RESOURCE_LOGGING" );
450 : if ( pLogFile )
451 : {
452 : SvFileStream aStm( OUString::createFromAscii( pLogFile ), STREAM_WRITE );
453 : aStm.Seek( STREAM_SEEK_TO_END );
454 : OStringBuffer aLine("FileName: ");
455 : aLine.append(OUStringToOString(aFileName,
456 : RTL_TEXTENCODING_UTF8));
457 : aStm.WriteLine(aLine.makeStringAndClear());
458 :
459 : for( boost::unordered_map<sal_uInt64, int>::const_iterator it = pResUseDump->begin();
460 : it != pResUseDump->end(); ++it )
461 : {
462 : sal_uInt64 nKeyId = it->first;
463 : aLine.append("Type/Id: ");
464 : aLine.append(sal::static_int_cast< sal_Int32 >((nKeyId >> 32) & 0xFFFFFFFF));
465 : aLine.append('/');
466 : aLine.append(sal::static_int_cast< sal_Int32 >(nKeyId & 0xFFFFFFFF));
467 : aStm.WriteLine(aLine.makeStringAndClear());
468 : }
469 : }
470 : }
471 : #endif
472 :
473 0 : delete pResUseDump;
474 0 : }
475 :
476 0 : bool InternalResMgr::Create()
477 : {
478 0 : ResMgrContainer::get();
479 0 : bool bDone = false;
480 :
481 0 : pStm = new SvFileStream( aFileName, (STREAM_READ | STREAM_SHARE_DENYWRITE | STREAM_NOCREATE) );
482 0 : if( pStm->GetError() == 0 )
483 : {
484 0 : sal_Int32 lContLen = 0;
485 :
486 0 : pStm->Seek( STREAM_SEEK_TO_END );
487 : /*
488 : if( ( pInternalResMgr->pHead = (RSHEADER_TYPE *)mmap( 0, nResourceFileSize,
489 : PROT_READ, MAP_PRIVATE,
490 : fRes, 0 ) ) != (RSHEADER_TYPE *)-1)
491 : */
492 0 : pStm->SeekRel( - (int)sizeof( lContLen ) );
493 0 : pStm->Read( &lContLen, sizeof( lContLen ) );
494 : // is bigendian, swab to the right endian
495 0 : lContLen = ResMgr::GetLong( &lContLen );
496 0 : pStm->SeekRel( -lContLen );
497 : // allocate stored ImpContent data (12 bytes per unit)
498 0 : sal_uInt8* pContentBuf = (sal_uInt8*)rtl_allocateMemory( lContLen );
499 0 : pStm->Read( pContentBuf, lContLen );
500 : // allocate ImpContent space (sizeof(ImpContent) per unit, not necessarily 12)
501 0 : pContent = (ImpContent *)rtl_allocateMemory( sizeof(ImpContent)*lContLen/12 );
502 : // Shorten to number of ImpContent
503 0 : nEntries = (sal_uInt32)lContLen / 12;
504 0 : bEqual2Content = true;
505 0 : bool bSorted = true;
506 0 : if( nEntries )
507 : {
508 : #ifdef DBG_UTIL
509 : const sal_Char* pLogFile = getenv( "STAR_RESOURCE_LOGGING" );
510 : if ( pLogFile )
511 : {
512 : pResUseDump = new boost::unordered_map<sal_uInt64, int>;
513 : for( sal_uInt32 i = 0; i < nEntries; ++i )
514 : (*pResUseDump)[pContent[i].nTypeAndId] = 1;
515 : }
516 : #endif
517 : // swap the content to the right endian
518 0 : pContent[0].nTypeAndId = ResMgr::GetUInt64( pContentBuf );
519 0 : pContent[0].nOffset = ResMgr::GetLong( pContentBuf+8 );
520 0 : sal_uInt32 nCount = nEntries - 1;
521 0 : for( sal_uInt32 i = 0,j=1; i < nCount; ++i,++j )
522 : {
523 : // swap the content to the right endian
524 0 : pContent[j].nTypeAndId = ResMgr::GetUInt64( pContentBuf + (12*j) );
525 0 : pContent[j].nOffset = ResMgr::GetLong( pContentBuf + (12*j+8) );
526 0 : if( pContent[i].nTypeAndId >= pContent[j].nTypeAndId )
527 0 : bSorted = false;
528 0 : if( (pContent[i].nTypeAndId & 0xFFFFFFFF00000000LL) == (pContent[j].nTypeAndId & 0xFFFFFFFF00000000LL)
529 0 : && pContent[i].nOffset >= pContent[j].nOffset )
530 0 : bEqual2Content = false;
531 : }
532 : }
533 0 : rtl_freeMemory( pContentBuf );
534 : OSL_ENSURE( bSorted, "content not sorted" );
535 : OSL_ENSURE( bEqual2Content, "resource structure wrong" );
536 0 : if( !bSorted )
537 0 : ::std::sort(pContent,pContent+nEntries,ImpContentLessCompare());
538 : // qsort( pContent, nEntries, sizeof( ImpContent ), Compare );
539 :
540 0 : bDone = true;
541 : }
542 :
543 0 : return bDone;
544 : }
545 :
546 :
547 0 : bool InternalResMgr::IsGlobalAvailable( RESOURCE_TYPE nRT, sal_uInt32 nId ) const
548 : {
549 : // Anfang der Strings suchen
550 : ImpContent aValue;
551 0 : aValue.nTypeAndId = ((sal_uInt64(nRT) << 32) | nId);
552 : ImpContent * pFind = ::std::lower_bound(pContent,
553 : pContent + nEntries,
554 : aValue,
555 0 : ImpContentLessCompare());
556 0 : return (pFind != (pContent + nEntries)) && (pFind->nTypeAndId == aValue.nTypeAndId);
557 : }
558 :
559 :
560 0 : void* InternalResMgr::LoadGlobalRes( RESOURCE_TYPE nRT, sal_uInt32 nId,
561 : void **pResHandle )
562 : {
563 : #ifdef DBG_UTIL
564 : if( pResUseDump )
565 : pResUseDump->erase( (sal_uInt64(nRT) << 32) | nId );
566 : #endif
567 : // search beginning of string
568 : ImpContent aValue;
569 0 : aValue.nTypeAndId = ((sal_uInt64(nRT) << 32) | nId);
570 0 : ImpContent* pEnd = (pContent + nEntries);
571 : ImpContent* pFind = ::std::lower_bound( pContent,
572 : pEnd,
573 : aValue,
574 0 : ImpContentLessCompare());
575 0 : if( pFind && (pFind != pEnd) && (pFind->nTypeAndId == aValue.nTypeAndId) )
576 : {
577 0 : if( nRT == RSC_STRING && bEqual2Content )
578 : {
579 : // string optimization
580 0 : if( !pStringBlock )
581 : {
582 : // search beginning of string
583 0 : ImpContent * pFirst = pFind;
584 0 : ImpContent * pLast = pFirst;
585 0 : while( pFirst > pContent && ((pFirst -1)->nTypeAndId >> 32) == RSC_STRING )
586 0 : --pFirst;
587 0 : while( pLast < pEnd && (pLast->nTypeAndId >> 32) == RSC_STRING )
588 0 : ++pLast;
589 0 : nOffCorrection = pFirst->nOffset;
590 : sal_uInt32 nSize;
591 0 : --pLast;
592 0 : pStm->Seek( pLast->nOffset );
593 : RSHEADER_TYPE aHdr;
594 0 : pStm->Read( &aHdr, sizeof( aHdr ) );
595 0 : nSize = pLast->nOffset + aHdr.GetGlobOff() - nOffCorrection;
596 0 : pStringBlock = (sal_uInt8*)rtl_allocateMemory( nSize );
597 0 : pStm->Seek( pFirst->nOffset );
598 0 : pStm->Read( pStringBlock, nSize );
599 : }
600 0 : *pResHandle = pStringBlock;
601 0 : return (sal_uInt8*)pStringBlock + pFind->nOffset - nOffCorrection;
602 : } // if( nRT == RSC_STRING && bEqual2Content )
603 : else
604 : {
605 0 : *pResHandle = 0;
606 : RSHEADER_TYPE aHeader;
607 0 : pStm->Seek( pFind->nOffset );
608 0 : pStm->Read( &aHeader, sizeof( RSHEADER_TYPE ) );
609 0 : void * pRes = rtl_allocateMemory( aHeader.GetGlobOff() );
610 0 : memcpy( pRes, &aHeader, sizeof( RSHEADER_TYPE ) );
611 0 : pStm->Read( (sal_uInt8*)pRes + sizeof( RSHEADER_TYPE ),
612 0 : aHeader.GetGlobOff() - sizeof( RSHEADER_TYPE ) );
613 0 : return pRes;
614 : }
615 : } // if( pFind && (pFind != pEnd) && (pFind->nTypeAndId == nValue) )
616 0 : *pResHandle = 0;
617 0 : return NULL;
618 : }
619 :
620 0 : void InternalResMgr::FreeGlobalRes( void * pResHandle, void * pResource )
621 : {
622 0 : if ( !pResHandle )
623 : // Free allocated resource
624 0 : rtl_freeMemory(pResource);
625 0 : }
626 :
627 : #ifdef DBG_UTIL
628 :
629 : OUString GetTypeRes_Impl( const ResId& rTypeId )
630 : {
631 : // Return on resource errors
632 : static bool bInUse = false;
633 : OUString aTypStr(OUString::number(rTypeId.GetId()));
634 :
635 : if ( !bInUse )
636 : {
637 : bInUse = true;
638 :
639 : ResId aResId( sal_uInt32(RSCVERSION_ID), *rTypeId.GetResMgr() );
640 : aResId.SetRT( RSC_VERSIONCONTROL );
641 :
642 : if ( rTypeId.GetResMgr()->GetResource( aResId ) )
643 : {
644 : rTypeId.SetRT( RSC_STRING );
645 : if ( rTypeId.GetResMgr()->IsAvailable( rTypeId ) )
646 : {
647 : aTypStr = rTypeId.toString();
648 : // Set class pointer to the end
649 : rTypeId.GetResMgr()->Increment( sizeof( RSHEADER_TYPE ) );
650 : }
651 : }
652 : bInUse = false;
653 : }
654 :
655 : return aTypStr;
656 : }
657 :
658 : void ResMgr::RscError_Impl( const sal_Char* pMessage, ResMgr* pResMgr,
659 : RESOURCE_TYPE nRT, sal_uInt32 nId,
660 : std::vector< ImpRCStack >& rResStack, int nDepth )
661 : {
662 : // create a separate ResMgr with its own stack
663 : // first get a second reference of the InternalResMgr
664 : InternalResMgr* pImp =
665 : ResMgrContainer::get().getResMgr( pResMgr->pImpRes->aPrefix,
666 : pResMgr->pImpRes->aLocale,
667 : true );
668 :
669 : ResMgr* pNewResMgr = new ResMgr( pImp );
670 :
671 : OStringBuffer aStr(OUStringToOString(pResMgr->GetFileName(),
672 : RTL_TEXTENCODING_UTF8));
673 :
674 : if (aStr.getLength())
675 : aStr.append('\n');
676 :
677 : aStr.append("Class: ");
678 : aStr.append(OUStringToOString(GetTypeRes_Impl(ResId(nRT, *pNewResMgr)),
679 : RTL_TEXTENCODING_UTF8));
680 : aStr.append(", Id: ");
681 : aStr.append(static_cast<sal_Int32>(nId));
682 : aStr.append(". ");
683 : aStr.append(pMessage);
684 :
685 : aStr.append("\nResource Stack\n");
686 : while( nDepth > 0 )
687 : {
688 : aStr.append("Class: ");
689 : aStr.append(OUStringToOString(GetTypeRes_Impl(
690 : ResId(rResStack[nDepth].pResource->GetRT(), *pNewResMgr)),
691 : RTL_TEXTENCODING_UTF8));
692 : aStr.append(", Id: ");
693 : aStr.append(static_cast<sal_Int32>(
694 : rResStack[nDepth].pResource->GetId()));
695 : nDepth--;
696 : }
697 :
698 : // clean up
699 : delete pNewResMgr;
700 :
701 : OSL_FAIL(aStr.getStr());
702 : }
703 :
704 : #endif
705 :
706 0 : static void RscException_Impl()
707 : {
708 0 : switch ( osl_raiseSignal( OSL_SIGNAL_USER_RESOURCEFAILURE, (void*)"" ) )
709 : {
710 : case osl_Signal_ActCallNextHdl:
711 0 : abort();
712 :
713 : case osl_Signal_ActIgnore:
714 0 : return;
715 :
716 : case osl_Signal_ActAbortApp:
717 0 : abort();
718 :
719 : default:
720 : case osl_Signal_ActKillApp:
721 0 : exit(-1);
722 : }
723 : }
724 :
725 0 : void ImpRCStack::Init( ResMgr* pMgr, const Resource* pObj, sal_uInt32 Id )
726 : {
727 0 : pResource = NULL;
728 0 : pClassRes = NULL;
729 0 : Flags = RC_NOTYPE;
730 0 : aResHandle = NULL;
731 0 : pResObj = pObj;
732 0 : nId = Id & ~RSC_DONTRELEASE; //TLX: Besser Init aendern
733 0 : pResMgr = pMgr;
734 0 : if ( !(Id & RSC_DONTRELEASE) )
735 0 : Flags |= RC_AUTORELEASE;
736 0 : }
737 :
738 0 : void ImpRCStack::Clear()
739 : {
740 0 : pResource = NULL;
741 0 : pClassRes = NULL;
742 0 : Flags = RC_NOTYPE;
743 0 : aResHandle = NULL;
744 0 : pResObj = NULL;
745 0 : nId = 0;
746 0 : pResMgr = NULL;
747 0 : }
748 :
749 0 : static RSHEADER_TYPE* LocalResource( const ImpRCStack* pStack,
750 : RESOURCE_TYPE nRTType,
751 : sal_uInt32 nId )
752 : {
753 : // Returns position of the resource if found or NULL otherwise
754 : RSHEADER_TYPE* pTmp; // Pointer to child resource
755 : RSHEADER_TYPE* pEnd; // Pointer to the end of this resource
756 :
757 0 : if ( pStack->pResource && pStack->pClassRes )
758 : {
759 : pTmp = (RSHEADER_TYPE*)
760 0 : ((sal_uInt8*)pStack->pResource + pStack->pResource->GetLocalOff());
761 : pEnd = (RSHEADER_TYPE*)
762 0 : ((sal_uInt8*)pStack->pResource + pStack->pResource->GetGlobOff());
763 0 : while ( pTmp != pEnd )
764 : {
765 0 : if ( pTmp->GetRT() == nRTType && pTmp->GetId() == nId )
766 0 : return pTmp;
767 0 : pTmp = (RSHEADER_TYPE*)((sal_uInt8*)pTmp + pTmp->GetGlobOff());
768 : }
769 : }
770 :
771 0 : return NULL;
772 : }
773 :
774 : void* ResMgr::pEmptyBuffer = NULL;
775 :
776 0 : void* ResMgr::getEmptyBuffer()
777 : {
778 0 : if( ! pEmptyBuffer )
779 0 : pEmptyBuffer = rtl_allocateZeroMemory( 1024 );
780 0 : return pEmptyBuffer;
781 : }
782 :
783 1 : void ResMgr::DestroyAllResMgr()
784 : {
785 : {
786 1 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
787 1 : if( pEmptyBuffer )
788 : {
789 0 : rtl_freeMemory( pEmptyBuffer );
790 0 : pEmptyBuffer = NULL;
791 : }
792 1 : ResMgrContainer::release();
793 : }
794 1 : delete pResMgrMutex;
795 1 : pResMgrMutex = NULL;
796 1 : }
797 :
798 0 : void ResMgr::Init( const OUString& rFileName )
799 : {
800 : (void) rFileName; // avoid warning about unused parameter
801 0 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
802 :
803 0 : if ( !pImpRes )
804 : {
805 : #ifdef DBG_UTIL
806 : OStringBuffer aStr("Resourcefile not found:\n");
807 : aStr.append(OUStringToOString(rFileName, RTL_TEXTENCODING_UTF8));
808 : OSL_FAIL(aStr.getStr());
809 : #endif
810 0 : RscException_Impl();
811 : }
812 : #ifdef DBG_UTIL
813 : else
814 : {
815 : void* aResHandle = 0; // Helper variable for resource handles
816 : void* pVoid; // Pointer on the resource
817 :
818 : pVoid = pImpRes->LoadGlobalRes( RSC_VERSIONCONTROL, RSCVERSION_ID,
819 : &aResHandle );
820 : if ( pVoid )
821 : InternalResMgr::FreeGlobalRes( aResHandle, pVoid );
822 : else
823 : {
824 : SAL_WARN("tools.rc", "Wrong version: " << pImpRes->aFileName);
825 : }
826 : }
827 : #endif
828 0 : nCurStack = -1;
829 0 : aStack.clear();
830 0 : pFallbackResMgr = pOriginalResMgr = NULL;
831 0 : incStack();
832 0 : }
833 :
834 0 : ResMgr::ResMgr( InternalResMgr * pImpMgr )
835 : {
836 0 : pImpRes = pImpMgr;
837 0 : Init( pImpMgr->aFileName );
838 0 : }
839 :
840 0 : ResMgr::~ResMgr()
841 : {
842 0 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
843 :
844 0 : ResMgrContainer::get().freeResMgr( pImpRes );
845 :
846 : // clean up possible left rc stack frames
847 0 : while( nCurStack > 0 )
848 : {
849 0 : if( ( aStack[nCurStack].Flags & (RC_GLOBAL | RC_NOTFOUND) ) == RC_GLOBAL )
850 0 : InternalResMgr::FreeGlobalRes( aStack[nCurStack].aResHandle,
851 0 : aStack[nCurStack].pResource );
852 0 : nCurStack--;
853 0 : }
854 0 : }
855 :
856 0 : void ResMgr::incStack()
857 : {
858 0 : nCurStack++;
859 0 : if( nCurStack >= int(aStack.size()) )
860 0 : aStack.push_back( ImpRCStack() );
861 0 : aStack[nCurStack].Clear();
862 :
863 : DBG_ASSERT( nCurStack < 32, "Resource stack unreasonably large" );
864 0 : }
865 :
866 0 : void ResMgr::decStack()
867 : {
868 : DBG_ASSERT( nCurStack > 0, "resource stack underrun !" );
869 0 : if( (aStack[nCurStack].Flags & RC_FALLBACK_UP) )
870 : {
871 0 : nCurStack--;
872 : // warning: this will delete *this, see below
873 0 : pOriginalResMgr->decStack();
874 : }
875 : else
876 : {
877 0 : ImpRCStack& rTop = aStack[nCurStack];
878 0 : if( (rTop.Flags & RC_FALLBACK_DOWN) )
879 : {
880 : #if OSL_DEBUG_LEVEL > 1
881 : OSL_TRACE( "returning from fallback %s",
882 : OUStringToOString(pFallbackResMgr->GetFileName(), osl_getThreadTextEncoding() ).getStr() );
883 : #endif
884 0 : delete pFallbackResMgr;
885 0 : pFallbackResMgr = NULL;
886 : }
887 0 : nCurStack--;
888 : }
889 0 : }
890 :
891 : #ifdef DBG_UTIL
892 :
893 : void ResMgr::TestStack( const Resource* pResObj )
894 : {
895 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
896 :
897 : int upperLimit = nCurStack;
898 :
899 : if ( upperLimit < 0 )
900 : {
901 : OSL_FAIL( "resource stack underrun!" );
902 : upperLimit = aStack.size() - 1;
903 : }
904 : else if ( upperLimit >= static_cast<int>(aStack.size()) )
905 : {
906 : OSL_FAIL( "stack occupation index > allocated stack size" );
907 : upperLimit = aStack.size() - 1;
908 : }
909 :
910 : if ( DbgIsResource() )
911 : {
912 : for( int i = 1; i <= upperLimit; ++i )
913 : {
914 : if ( aStack[i].pResObj == pResObj )
915 : {
916 : RscError_Impl( "Resource not freed! ", this,
917 : aStack[i].pResource->GetRT(),
918 : aStack[i].pResource->GetId(),
919 : aStack, i-1 );
920 : }
921 : }
922 : }
923 : }
924 :
925 : #endif
926 :
927 0 : bool ResMgr::IsAvailable( const ResId& rId, const Resource* pResObj ) const
928 : {
929 0 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
930 :
931 0 : bool bAvailable = false;
932 0 : RSHEADER_TYPE* pClassRes = rId.GetpResource();
933 0 : RESOURCE_TYPE nRT = rId.GetRT2();
934 0 : sal_uInt32 nId = rId.GetId();
935 0 : const ResMgr* pMgr = rId.GetResMgr();
936 :
937 0 : if ( !pMgr )
938 0 : pMgr = this;
939 :
940 0 : if( pMgr->pFallbackResMgr )
941 : {
942 0 : ResId aId( rId );
943 0 : aId.SetResMgr( NULL );
944 0 : return pMgr->pFallbackResMgr->IsAvailable( aId, pResObj );
945 : }
946 :
947 0 : if ( !pResObj || pResObj == pMgr->aStack[pMgr->nCurStack].pResObj )
948 : {
949 0 : if ( !pClassRes )
950 0 : pClassRes = LocalResource( &pMgr->aStack[pMgr->nCurStack], nRT, nId );
951 0 : if ( pClassRes )
952 : {
953 0 : if ( pClassRes->GetRT() == nRT )
954 0 : bAvailable = true;
955 : }
956 : }
957 :
958 0 : if ( !pClassRes )
959 0 : bAvailable = pMgr->pImpRes->IsGlobalAvailable( nRT, nId );
960 :
961 0 : return bAvailable;
962 : }
963 :
964 0 : void* ResMgr::GetClass()
965 : {
966 0 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
967 :
968 0 : if( pFallbackResMgr )
969 0 : return pFallbackResMgr->GetClass();
970 :
971 0 : return aStack[nCurStack].pClassRes;
972 : }
973 :
974 0 : bool ResMgr::GetResource( const ResId& rId, const Resource* pResObj )
975 : {
976 0 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
977 :
978 0 : if( pFallbackResMgr )
979 : {
980 0 : ResId aId( rId );
981 0 : aId.SetResMgr( NULL );
982 0 : return pFallbackResMgr->GetResource( aId, pResObj );
983 : }
984 :
985 0 : ResMgr* pMgr = rId.GetResMgr();
986 0 : if ( pMgr && (this != pMgr) )
987 0 : return pMgr->GetResource( rId, pResObj );
988 :
989 : // normally Increment will pop the context; this is
990 : // not possible in RC_NOTFOUND case, so pop a frame here
991 0 : ImpRCStack* pTop = &aStack[nCurStack];
992 0 : if( (pTop->Flags & RC_NOTFOUND) )
993 : {
994 0 : decStack();
995 : }
996 :
997 0 : RSHEADER_TYPE* pClassRes = rId.GetpResource();
998 0 : RESOURCE_TYPE nRT = rId.GetRT2();
999 0 : sal_uInt32 nId = rId.GetId();
1000 :
1001 0 : incStack();
1002 0 : pTop = &aStack[nCurStack];
1003 : pTop->Init( pMgr, pResObj, nId |
1004 0 : (rId.IsAutoRelease() ? 0 : RSC_DONTRELEASE) );
1005 :
1006 0 : if ( pClassRes )
1007 : {
1008 0 : if ( pClassRes->GetRT() == nRT )
1009 0 : pTop->pClassRes = pClassRes;
1010 : else
1011 : {
1012 : #ifdef DBG_UTIL
1013 : RscError_Impl( "Different class and resource type!",
1014 : this, nRT, nId, aStack, nCurStack-1 );
1015 : #endif
1016 0 : pTop->Flags |= RC_NOTFOUND;
1017 0 : pTop->pClassRes = getEmptyBuffer();
1018 0 : pTop->pResource = (RSHEADER_TYPE*)pTop->pClassRes;
1019 0 : return false;
1020 : }
1021 : }
1022 : else
1023 : {
1024 : OSL_ENSURE( nCurStack > 0, "stack of 1 to shallow" );
1025 0 : pTop->pClassRes = LocalResource( &aStack[nCurStack-1], nRT, nId );
1026 : }
1027 :
1028 0 : if ( pTop->pClassRes )
1029 : // lokale Resource, nicht system Resource
1030 0 : pTop->pResource = (RSHEADER_TYPE *)pTop->pClassRes;
1031 : else
1032 : {
1033 0 : pTop->pClassRes = pImpRes->LoadGlobalRes( nRT, nId, &pTop->aResHandle );
1034 0 : if ( pTop->pClassRes )
1035 : {
1036 0 : pTop->Flags |= RC_GLOBAL;
1037 0 : pTop->pResource = (RSHEADER_TYPE *)pTop->pClassRes;
1038 : }
1039 : else
1040 : {
1041 : // try to get a fallback resource
1042 0 : pFallbackResMgr = CreateFallbackResMgr( rId, pResObj );
1043 0 : if( pFallbackResMgr )
1044 : {
1045 0 : pTop->Flags |= RC_FALLBACK_DOWN;
1046 : #ifdef DBG_UTIL
1047 : OStringBuffer aMess("found resource ");
1048 : aMess.append(static_cast<sal_Int32>(nId));
1049 : aMess.append(" in fallback ");
1050 : aMess.append(OUStringToOString(
1051 : pFallbackResMgr->GetFileName(),
1052 : osl_getThreadTextEncoding()));
1053 : aMess.append('\n');
1054 : RscError_Impl(aMess.getStr(),
1055 : this, nRT, nId, aStack, nCurStack-1);
1056 : #endif
1057 : }
1058 : else
1059 : {
1060 : #ifdef DBG_UTIL
1061 : RscError_Impl( "Cannot load resource! ",
1062 : this, nRT, nId, aStack, nCurStack-1 );
1063 : #endif
1064 0 : pTop->Flags |= RC_NOTFOUND;
1065 0 : pTop->pClassRes = getEmptyBuffer();
1066 0 : pTop->pResource = (RSHEADER_TYPE*)pTop->pClassRes;
1067 0 : return false;
1068 : }
1069 : }
1070 : }
1071 :
1072 0 : return true;
1073 : }
1074 :
1075 0 : void * ResMgr::GetResourceSkipHeader( const ResId& rResId, ResMgr ** ppResMgr )
1076 : {
1077 0 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1078 :
1079 : DBG_ASSERT( rResId.GetResMgr(), "illegal ResId without ResMgr" );
1080 0 : *ppResMgr = rResId.GetResMgr();
1081 0 : if( *ppResMgr )
1082 : {
1083 0 : (*ppResMgr)->GetResource( rResId );
1084 0 : (*ppResMgr)->Increment( sizeof( RSHEADER_TYPE ) );
1085 0 : return (*ppResMgr)->GetClass();
1086 : }
1087 0 : return getEmptyBuffer();
1088 : }
1089 :
1090 0 : void ResMgr::PopContext( const Resource* pResObj )
1091 : {
1092 0 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1093 :
1094 0 : if( pFallbackResMgr )
1095 : {
1096 0 : pFallbackResMgr->PopContext( pResObj );
1097 0 : return;
1098 : }
1099 :
1100 : #ifdef DBG_UTIL
1101 : if ( DbgIsResource() )
1102 : {
1103 : if ( (aStack[nCurStack].pResObj != pResObj) || nCurStack == 0 )
1104 : {
1105 : RscError_Impl( "Cannot free resource! ", this,
1106 : RSC_NOTYPE, 0, aStack, nCurStack );
1107 : }
1108 : }
1109 : #endif
1110 :
1111 0 : if ( nCurStack > 0 )
1112 : {
1113 0 : ImpRCStack* pTop = &aStack[nCurStack];
1114 : #ifdef DBG_UTIL
1115 : if ( DbgIsResource() && !(pTop->Flags & RC_NOTFOUND) )
1116 : {
1117 : void* pRes = (sal_uInt8*)pTop->pResource +
1118 : pTop->pResource->GetLocalOff();
1119 :
1120 : if ( pTop->pClassRes != pRes )
1121 : {
1122 : RscError_Impl( "Classpointer not at the end!",
1123 : this, pTop->pResource->GetRT(),
1124 : pTop->pResource->GetId(),
1125 : aStack, nCurStack-1 );
1126 : }
1127 : }
1128 : #endif
1129 :
1130 : // free resource
1131 0 : if( (pTop->Flags & (RC_GLOBAL | RC_NOTFOUND)) == RC_GLOBAL )
1132 : // free global resource if resource is foreign
1133 0 : InternalResMgr::FreeGlobalRes( pTop->aResHandle, pTop->pResource );
1134 0 : decStack();
1135 0 : }
1136 : }
1137 :
1138 0 : RSHEADER_TYPE* ResMgr::CreateBlock( const ResId& rId )
1139 : {
1140 0 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1141 :
1142 0 : if( pFallbackResMgr )
1143 : {
1144 0 : ResId aId( rId );
1145 0 : aId.SetResMgr( NULL );
1146 0 : return pFallbackResMgr->CreateBlock( aId );
1147 : }
1148 :
1149 0 : RSHEADER_TYPE* pHeader = NULL;
1150 0 : if ( GetResource( rId ) )
1151 : {
1152 : // Pointer is at the beginning of the resource, thus
1153 : // class pointer points to the header, and the remaining size
1154 : // equals to total size of allocated memory
1155 0 : pHeader = (RSHEADER_TYPE*)rtl_allocateMemory( GetRemainSize() );
1156 0 : memcpy( pHeader, GetClass(), GetRemainSize() );
1157 0 : Increment( pHeader->GetLocalOff() ); //ans Ende setzen
1158 0 : if ( pHeader->GetLocalOff() != pHeader->GetGlobOff() )
1159 : // Has sub-resources, thus release them as well
1160 0 : PopContext();
1161 : }
1162 :
1163 0 : return pHeader;
1164 : }
1165 :
1166 0 : sal_Int16 ResMgr::GetShort( void * pShort )
1167 : {
1168 0 : return ((*((sal_uInt8*)pShort + 0) << 8) |
1169 0 : (*((sal_uInt8*)pShort + 1) << 0) );
1170 : }
1171 :
1172 0 : sal_Int32 ResMgr::GetLong( void * pLong )
1173 : {
1174 0 : return ((*((sal_uInt8*)pLong + 0) << 24) |
1175 0 : (*((sal_uInt8*)pLong + 1) << 16) |
1176 0 : (*((sal_uInt8*)pLong + 2) << 8) |
1177 0 : (*((sal_uInt8*)pLong + 3) << 0) );
1178 : }
1179 :
1180 0 : sal_uInt64 ResMgr::GetUInt64( void* pDatum )
1181 : {
1182 0 : return ((sal_uInt64(*((sal_uInt8*)pDatum + 0)) << 56) |
1183 0 : (sal_uInt64(*((sal_uInt8*)pDatum + 1)) << 48) |
1184 0 : (sal_uInt64(*((sal_uInt8*)pDatum + 2)) << 40) |
1185 0 : (sal_uInt64(*((sal_uInt8*)pDatum + 3)) << 32) |
1186 0 : (sal_uInt64(*((sal_uInt8*)pDatum + 4)) << 24) |
1187 0 : (sal_uInt64(*((sal_uInt8*)pDatum + 5)) << 16) |
1188 0 : (sal_uInt64(*((sal_uInt8*)pDatum + 6)) << 8) |
1189 0 : (sal_uInt64(*((sal_uInt8*)pDatum + 7)) << 0) );
1190 : }
1191 :
1192 0 : sal_uInt32 ResMgr::GetStringWithoutHook( OUString& rStr, const sal_uInt8* pStr )
1193 : {
1194 0 : sal_uInt32 nLen=0;
1195 0 : sal_uInt32 nRet = GetStringSize( pStr, nLen );
1196 0 : const sal_Char* str = reinterpret_cast< const sal_Char* >( pStr );
1197 0 : OUString aString( str, strlen( str ), RTL_TEXTENCODING_UTF8,
1198 : RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_MAPTOPRIVATE |
1199 : RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT |
1200 0 : RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT );
1201 0 : rStr = aString;
1202 0 : return nRet;
1203 : }
1204 :
1205 0 : sal_uInt32 ResMgr::GetString( OUString& rStr, const sal_uInt8* pStr )
1206 : {
1207 0 : OUString aString;
1208 0 : sal_uInt32 nRet = GetStringWithoutHook( aString, pStr );
1209 0 : if ( pImplResHookProc )
1210 0 : aString = pImplResHookProc( aString );
1211 0 : rStr = aString;
1212 0 : return nRet;
1213 : }
1214 :
1215 0 : sal_uInt32 ResMgr::GetByteString( OString& rStr, const sal_uInt8* pStr )
1216 : {
1217 0 : sal_uInt32 nLen=0;
1218 0 : sal_uInt32 nRet = GetStringSize( pStr, nLen );
1219 0 : rStr = OString( (const sal_Char*)pStr, nLen );
1220 0 : return nRet;
1221 : }
1222 :
1223 0 : sal_uInt32 ResMgr::GetStringSize( const sal_uInt8* pStr, sal_uInt32& nLen )
1224 : {
1225 0 : nLen = static_cast< sal_uInt32 >( strlen( (const char*)pStr ) );
1226 0 : return GetStringSize( nLen );
1227 : }
1228 :
1229 0 : sal_uInt32 ResMgr::GetRemainSize()
1230 : {
1231 0 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1232 :
1233 0 : if( pFallbackResMgr )
1234 0 : return pFallbackResMgr->GetRemainSize();
1235 :
1236 0 : const ImpRCStack& rTop = aStack[nCurStack];
1237 0 : return (sal_uInt32)((sal_IntPtr)(sal_uInt8 *)rTop.pResource +
1238 0 : rTop.pResource->GetLocalOff() -
1239 0 : (sal_IntPtr)(sal_uInt8 *)rTop.pClassRes);
1240 : }
1241 :
1242 0 : void* ResMgr::Increment( sal_uInt32 nSize )
1243 : {
1244 0 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1245 :
1246 0 : if( pFallbackResMgr )
1247 0 : return pFallbackResMgr->Increment( nSize );
1248 :
1249 0 : ImpRCStack& rStack = aStack[nCurStack];
1250 0 : if( (rStack.Flags & RC_NOTFOUND) )
1251 0 : return rStack.pClassRes;
1252 :
1253 0 : sal_uInt8* pClassRes = (sal_uInt8*)rStack.pClassRes + nSize;
1254 :
1255 0 : rStack.pClassRes = pClassRes;
1256 :
1257 0 : RSHEADER_TYPE* pRes = rStack.pResource;
1258 :
1259 0 : sal_uInt32 nLocalOff = pRes->GetLocalOff();
1260 0 : if ( (pRes->GetGlobOff() == nLocalOff) &&
1261 0 : (((char*)pRes + nLocalOff) == rStack.pClassRes) &&
1262 0 : (rStack.Flags & RC_AUTORELEASE))
1263 : {
1264 0 : PopContext( rStack.pResObj );
1265 : }
1266 :
1267 0 : return pClassRes;
1268 : }
1269 :
1270 0 : ResMgr* ResMgr::CreateFallbackResMgr( const ResId& rId, const Resource* pResource )
1271 : {
1272 0 : ResMgr *pFallback = NULL;
1273 0 : if( nCurStack > 0 )
1274 : {
1275 : // get the next fallback level in resource file scope
1276 0 : InternalResMgr* pRes = ResMgrContainer::get().getNextFallback( pImpRes );
1277 0 : if( pRes )
1278 : {
1279 : // check that the fallback locale is not already in the chain of
1280 : // fallbacks - prevent fallback loops
1281 0 : ResMgr* pResMgr = this;
1282 0 : while( pResMgr && (pResMgr->pImpRes->aLocale != pRes->aLocale))
1283 : {
1284 0 : pResMgr = pResMgr->pOriginalResMgr;
1285 : }
1286 0 : if( pResMgr )
1287 : {
1288 : // found a recursion, no fallback possible
1289 0 : ResMgrContainer::get().freeResMgr( pRes );
1290 0 : return NULL;
1291 : }
1292 : OSL_TRACE( "trying fallback: %s", OUStringToOString( pRes->aFileName, osl_getThreadTextEncoding() ).getStr() );
1293 0 : pFallback = new ResMgr( pRes );
1294 0 : pFallback->pOriginalResMgr = this;
1295 : // try to recreate the resource stack
1296 0 : bool bHaveStack = true;
1297 0 : for( int i = 1; i < nCurStack; i++ )
1298 : {
1299 0 : if( !aStack[i].pResource )
1300 : {
1301 0 : bHaveStack = false;
1302 0 : break;
1303 : }
1304 0 : ResId aId( aStack[i].pResource->GetId(), *pFallbackResMgr );
1305 0 : aId.SetRT( aStack[i].pResource->GetRT() );
1306 0 : if( !pFallback->GetResource( aId ) )
1307 : {
1308 0 : bHaveStack = false;
1309 0 : break;
1310 : }
1311 : }
1312 0 : if( bHaveStack )
1313 : {
1314 0 : ResId aId( rId.GetId(), *pFallback );
1315 0 : aId.SetRT( rId.GetRT() );
1316 0 : if( !pFallback->GetResource( aId, pResource ) )
1317 0 : bHaveStack = false;
1318 : else
1319 0 : pFallback->aStack[pFallback->nCurStack].Flags |= RC_FALLBACK_UP;
1320 : }
1321 0 : if( !bHaveStack )
1322 : {
1323 0 : delete pFallback;
1324 0 : pFallback = NULL;
1325 : }
1326 : }
1327 : }
1328 0 : return pFallback;
1329 : }
1330 :
1331 0 : ResMgr* ResMgr::CreateResMgr( const sal_Char* pPrefixName,
1332 : LanguageTag aLocale )
1333 : {
1334 0 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1335 :
1336 0 : OUString aPrefix( pPrefixName, strlen( pPrefixName ), osl_getThreadTextEncoding() );
1337 :
1338 0 : if( aLocale.isSystemLocale() )
1339 0 : aLocale = ResMgrContainer::get().getDefLocale();
1340 :
1341 0 : InternalResMgr* pImp = ResMgrContainer::get().getResMgr( aPrefix, aLocale );
1342 0 : return pImp ? new ResMgr( pImp ) : NULL;
1343 : }
1344 :
1345 0 : ResMgr* ResMgr::SearchCreateResMgr(
1346 : const sal_Char* pPrefixName,
1347 : LanguageTag& rLocale )
1348 : {
1349 0 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1350 :
1351 0 : OUString aPrefix( pPrefixName, strlen( pPrefixName ), osl_getThreadTextEncoding() );
1352 :
1353 0 : if( rLocale.isSystemLocale() )
1354 0 : rLocale = ResMgrContainer::get().getDefLocale();
1355 :
1356 0 : InternalResMgr* pImp = ResMgrContainer::get().getResMgr( aPrefix, rLocale );
1357 0 : return pImp ? new ResMgr( pImp ) : NULL;
1358 : }
1359 :
1360 0 : sal_Int16 ResMgr::ReadShort()
1361 : {
1362 0 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1363 :
1364 0 : if( pFallbackResMgr )
1365 0 : return pFallbackResMgr->ReadShort();
1366 :
1367 0 : sal_Int16 n = GetShort( GetClass() );
1368 0 : Increment( sizeof( sal_Int16 ) );
1369 0 : return n;
1370 : }
1371 :
1372 0 : sal_Int32 ResMgr::ReadLong()
1373 : {
1374 0 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1375 :
1376 0 : if( pFallbackResMgr )
1377 0 : return pFallbackResMgr->ReadLong();
1378 :
1379 0 : sal_Int32 n = GetLong( GetClass() );
1380 0 : Increment( sizeof( sal_Int32 ) );
1381 0 : return n;
1382 : }
1383 :
1384 0 : OUString ResMgr::ReadStringWithoutHook()
1385 : {
1386 0 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1387 :
1388 0 : if( pFallbackResMgr )
1389 0 : return pFallbackResMgr->ReadStringWithoutHook();
1390 :
1391 0 : OUString aRet;
1392 :
1393 0 : const ImpRCStack& rTop = aStack[nCurStack];
1394 0 : if( (rTop.Flags & RC_NOTFOUND) )
1395 : {
1396 : #if OSL_DEBUG_LEVEL > 0
1397 : aRet = "<resource not found>";
1398 : #endif
1399 : }
1400 : else
1401 0 : Increment( GetStringWithoutHook( aRet, (const sal_uInt8*)GetClass() ) );
1402 :
1403 0 : return aRet;
1404 : }
1405 :
1406 0 : OUString ResMgr::ReadString()
1407 : {
1408 0 : OUString aRet = ReadStringWithoutHook();
1409 0 : if ( pImplResHookProc )
1410 0 : aRet = pImplResHookProc( aRet );
1411 0 : return aRet;
1412 : }
1413 :
1414 0 : OString ResMgr::ReadByteString()
1415 : {
1416 0 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1417 :
1418 0 : if( pFallbackResMgr )
1419 0 : return pFallbackResMgr->ReadByteString();
1420 :
1421 0 : OString aRet;
1422 :
1423 0 : const ImpRCStack& rTop = aStack[nCurStack];
1424 0 : if( (rTop.Flags & RC_NOTFOUND) )
1425 : {
1426 : #if OSL_DEBUG_LEVEL > 0
1427 : aRet = OString( "<resource not found>" );
1428 : #endif
1429 : }
1430 : else
1431 0 : Increment( GetByteString( aRet, (const sal_uInt8*)GetClass() ) );
1432 :
1433 0 : return aRet;
1434 : }
1435 :
1436 0 : OString ResMgr::GetAutoHelpId()
1437 : {
1438 0 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1439 :
1440 0 : if( pFallbackResMgr )
1441 0 : return pFallbackResMgr->GetAutoHelpId();
1442 :
1443 : OSL_ENSURE( nCurStack, "resource stack empty in Auto help id generation" );
1444 0 : if( nCurStack < 1 || nCurStack > 2 )
1445 0 : return OString();
1446 :
1447 : // prepare HID, start with resource prefix
1448 0 : OStringBuffer aHID( 32 );
1449 0 : aHID.append( OUStringToOString( pImpRes->aPrefix, RTL_TEXTENCODING_UTF8 ) );
1450 0 : aHID.append( '.' );
1451 :
1452 : // append type
1453 0 : const ImpRCStack *pRC = StackTop();
1454 : OSL_ENSURE( pRC, "missing resource stack level" );
1455 :
1456 0 : if ( nCurStack == 1 )
1457 : {
1458 : // auto help ids for top level windows
1459 0 : switch( pRC->pResource->GetRT() ) {
1460 0 : case RSC_DOCKINGWINDOW: aHID.append( "DockingWindow" ); break;
1461 0 : case RSC_WORKWIN: aHID.append( "WorkWindow" ); break;
1462 0 : case RSC_MODELESSDIALOG: aHID.append( "ModelessDialog" ); break;
1463 0 : case RSC_FLOATINGWINDOW: aHID.append( "FloatingWindow" ); break;
1464 0 : case RSC_MODALDIALOG: aHID.append( "ModalDialog" ); break;
1465 0 : case RSC_TABPAGE: aHID.append( "TabPage" ); break;
1466 0 : default: return OString();
1467 : }
1468 : }
1469 : else
1470 : {
1471 : // only controls with the following parents get auto help ids
1472 0 : const ImpRCStack *pRC1 = StackTop(1);
1473 0 : switch( pRC1->pResource->GetRT() ) {
1474 : case RSC_DOCKINGWINDOW:
1475 : case RSC_WORKWIN:
1476 : case RSC_MODELESSDIALOG:
1477 : case RSC_FLOATINGWINDOW:
1478 : case RSC_MODALDIALOG:
1479 : case RSC_TABPAGE:
1480 : // intentionally no breaks!
1481 : // auto help ids for controls
1482 0 : switch( pRC->pResource->GetRT() ) {
1483 0 : case RSC_TABCONTROL: aHID.append( "TabControl" ); break;
1484 0 : case RSC_RADIOBUTTON: aHID.append( "RadioButton" ); break;
1485 0 : case RSC_CHECKBOX: aHID.append( "CheckBox" ); break;
1486 0 : case RSC_TRISTATEBOX: aHID.append( "TriStateBox" ); break;
1487 0 : case RSC_EDIT: aHID.append( "Edit" ); break;
1488 0 : case RSC_MULTILINEEDIT: aHID.append( "MultiLineEdit" ); break;
1489 0 : case RSC_MULTILISTBOX: aHID.append( "MultiListBox" ); break;
1490 0 : case RSC_LISTBOX: aHID.append( "ListBox" ); break;
1491 0 : case RSC_COMBOBOX: aHID.append( "ComboBox" ); break;
1492 0 : case RSC_PUSHBUTTON: aHID.append( "PushButton" ); break;
1493 0 : case RSC_SPINFIELD: aHID.append( "SpinField" ); break;
1494 0 : case RSC_PATTERNFIELD: aHID.append( "PatternField" ); break;
1495 0 : case RSC_NUMERICFIELD: aHID.append( "NumericField" ); break;
1496 0 : case RSC_METRICFIELD: aHID.append( "MetricField" ); break;
1497 0 : case RSC_DATEFIELD: aHID.append( "DateField" ); break;
1498 0 : case RSC_TIMEFIELD: aHID.append( "TimeField" ); break;
1499 0 : case RSC_NUMERICBOX: aHID.append( "NumericBox" ); break;
1500 0 : case RSC_IMAGEBUTTON: aHID.append( "ImageButton" ); break;
1501 0 : case RSC_MENUBUTTON: aHID.append( "MenuButton" ); break;
1502 : default:
1503 : // no type, no auto HID
1504 0 : return OString();
1505 : }
1506 0 : break;
1507 : default:
1508 0 : return OString();
1509 : }
1510 : }
1511 :
1512 : // append resource id hierarchy
1513 0 : for( int nOff = nCurStack-1; nOff >= 0; nOff-- )
1514 : {
1515 0 : aHID.append( '.' );
1516 0 : pRC = StackTop( nOff );
1517 :
1518 : OSL_ENSURE( pRC->pResource, "missing resource in resource stack level !" );
1519 0 : if( pRC->pResource )
1520 0 : aHID.append( sal_Int32( pRC->pResource->GetId() ) );
1521 : }
1522 :
1523 0 : return aHID.makeStringAndClear();
1524 : }
1525 :
1526 0 : void ResMgr::SetReadStringHook( ResHookProc pProc )
1527 : {
1528 0 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1529 0 : pImplResHookProc = pProc;
1530 0 : }
1531 :
1532 0 : ResHookProc ResMgr::GetReadStringHook()
1533 : {
1534 0 : return pImplResHookProc;
1535 : }
1536 :
1537 0 : void ResMgr::SetDefaultLocale( const LanguageTag& rLocale )
1538 : {
1539 0 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1540 0 : ResMgrContainer::get().setDefLocale( rLocale );
1541 0 : }
1542 :
1543 0 : const OUString& ResMgr::GetFileName() const
1544 : {
1545 0 : return pImpRes->aFileName;
1546 : }
1547 :
1548 0 : SimpleResMgr::SimpleResMgr( const sal_Char* pPrefixName,
1549 0 : const LanguageTag& rLocale )
1550 : {
1551 0 : OUString aPrefix( pPrefixName, strlen( pPrefixName ), osl_getThreadTextEncoding() );
1552 0 : LanguageTag aLocale( rLocale );
1553 :
1554 0 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1555 0 : if( aLocale.isSystemLocale() )
1556 0 : aLocale = ResMgrContainer::get().getDefLocale();
1557 :
1558 0 : m_pResImpl = ResMgrContainer::get().getResMgr( aPrefix, aLocale, true );
1559 0 : DBG_ASSERT( m_pResImpl, "SimpleResMgr::SimpleResMgr : have no impl class !" );
1560 0 : }
1561 :
1562 0 : SimpleResMgr::~SimpleResMgr()
1563 : {
1564 0 : delete m_pResImpl;
1565 0 : }
1566 :
1567 0 : SimpleResMgr* SimpleResMgr::Create( const sal_Char* pPrefixName, LanguageTag aLocale )
1568 : {
1569 0 : return new SimpleResMgr( pPrefixName, aLocale );
1570 : }
1571 :
1572 0 : bool SimpleResMgr::IsAvailable( RESOURCE_TYPE _resourceType, sal_uInt32 _resourceId )
1573 : {
1574 0 : osl::MutexGuard aGuard(m_aAccessSafety);
1575 :
1576 0 : if ( ( RSC_STRING != _resourceType ) && ( RSC_RESOURCE != _resourceType ) )
1577 0 : return false;
1578 :
1579 : DBG_ASSERT( m_pResImpl, "SimpleResMgr::IsAvailable: have no impl class !" );
1580 0 : return m_pResImpl->IsGlobalAvailable( _resourceType, _resourceId );
1581 : }
1582 :
1583 0 : OUString SimpleResMgr::ReadString( sal_uInt32 nId )
1584 : {
1585 0 : osl::MutexGuard aGuard(m_aAccessSafety);
1586 :
1587 : DBG_ASSERT( m_pResImpl, "SimpleResMgr::ReadString : have no impl class !" );
1588 : // perhaps constructed with an invalid filename ?
1589 :
1590 0 : OUString sReturn;
1591 0 : if ( !m_pResImpl )
1592 0 : return sReturn;
1593 :
1594 0 : void* pResHandle = NULL;
1595 0 : InternalResMgr* pFallback = m_pResImpl;
1596 0 : RSHEADER_TYPE* pResHeader = (RSHEADER_TYPE*)m_pResImpl->LoadGlobalRes( RSC_STRING, nId, &pResHandle );
1597 0 : if ( !pResHeader )
1598 : {
1599 0 : osl::Guard<osl::Mutex> aGuard2( getResMgrMutex() );
1600 :
1601 : // try fallback
1602 0 : while( ! pResHandle && pFallback )
1603 : {
1604 0 : InternalResMgr* pOldFallback = pFallback;
1605 0 : pFallback = ResMgrContainer::get().getNextFallback( pFallback );
1606 0 : if( pOldFallback != m_pResImpl )
1607 0 : ResMgrContainer::get().freeResMgr( pOldFallback );
1608 0 : if( pFallback )
1609 : {
1610 : // handle possible recursion
1611 0 : if( pFallback->aLocale != m_pResImpl->aLocale )
1612 : {
1613 0 : pResHeader = (RSHEADER_TYPE*)pFallback->LoadGlobalRes( RSC_STRING, nId, &pResHandle );
1614 : }
1615 : else
1616 : {
1617 0 : ResMgrContainer::get().freeResMgr( pFallback );
1618 0 : pFallback = NULL;
1619 : }
1620 : }
1621 : }
1622 0 : if( ! pResHandle )
1623 : // no such resource
1624 0 : return sReturn;
1625 : }
1626 :
1627 : // sal_uIntPtr nLen = pResHeader->GetLocalOff() - sizeof(RSHEADER_TYPE);
1628 0 : ResMgr::GetString( sReturn, (const sal_uInt8*)(pResHeader+1) );
1629 :
1630 : // not necessary with te current implementation which holds the string table permanently, but to be sure ....
1631 : // note: pFallback cannot be NULL here and is either the fallback or m_pResImpl
1632 0 : InternalResMgr::FreeGlobalRes( pResHeader, pResHandle );
1633 0 : if( m_pResImpl != pFallback )
1634 : {
1635 0 : osl::Guard<osl::Mutex> aGuard2( getResMgrMutex() );
1636 :
1637 0 : ResMgrContainer::get().freeResMgr( pFallback );
1638 : }
1639 0 : return sReturn;
1640 : }
1641 :
1642 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|