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 9468392 : static osl::Mutex& getResMgrMutex()
63 : {
64 9468392 : if( !pResMgrMutex )
65 : {
66 373 : osl::Guard<osl::Mutex> aGuard( *osl::Mutex::getGlobalMutex() );
67 373 : if( ! pResMgrMutex )
68 373 : pResMgrMutex = new osl::Mutex();
69 : }
70 9468392 : 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 20552 : struct ContainerElement
113 : {
114 : InternalResMgr* pResMgr;
115 : OUString aFileURL;
116 : int nRefCount;
117 : int nLoadCount;
118 :
119 20888 : ContainerElement() :
120 : pResMgr( NULL ),
121 : nRefCount( 0 ),
122 20888 : nLoadCount( 0 )
123 20888 : {}
124 : };
125 :
126 : boost::unordered_map< OUString, ContainerElement, OUStringHash> m_aResFiles;
127 : LanguageTag m_aDefLocale;
128 :
129 373 : 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 1389 : void setDefLocale( const LanguageTag& rLocale )
147 1389 : { m_aDefLocale = rLocale; }
148 1620 : const LanguageTag& getDefLocale() const
149 1620 : { return m_aDefLocale; }
150 : };
151 :
152 : ResMgrContainer* ResMgrContainer::pOneInstance = NULL;
153 :
154 12399 : ResMgrContainer& ResMgrContainer::get()
155 : {
156 12399 : if( ! pOneInstance )
157 373 : pOneInstance = new ResMgrContainer();
158 12399 : return *pOneInstance;
159 : }
160 :
161 734 : ResMgrContainer::~ResMgrContainer()
162 : {
163 62757 : for( boost::unordered_map< OUString, ContainerElement, OUStringHash >::iterator it =
164 42205 : 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 20552 : delete it->second.pResMgr;
170 : }
171 367 : }
172 :
173 367 : void ResMgrContainer::release()
174 : {
175 367 : delete pOneInstance;
176 367 : pOneInstance = NULL;
177 367 : }
178 :
179 373 : void ResMgrContainer::init()
180 : {
181 : assert( m_aResFiles.empty() );
182 :
183 : // get resource path
184 373 : OUString uri("$BRAND_BASE_DIR/" LIBO_SHARE_RESOURCE_FOLDER "/");
185 373 : rtl::Bootstrap::expandMacros(uri); //TODO: detect failure
186 :
187 : // collect all possible resource files
188 746 : Directory aDir( uri );
189 373 : if( aDir.open() == FileBase::E_None )
190 : {
191 373 : DirectoryItem aItem;
192 21634 : while( aDir.getNextItem( aItem ) == FileBase::E_None )
193 : {
194 20888 : FileStatus aStatus(osl_FileStatus_Mask_FileName);
195 20888 : if( aItem.getFileStatus( aStatus ) == FileBase::E_None )
196 : {
197 20888 : OUString aFileName = aStatus.getFileName();
198 20888 : if( ! aFileName.endsWithIgnoreAsciiCase( ".res" ) )
199 0 : continue;
200 41776 : OUString aResName = aFileName.copy( 0, aFileName.getLength() - strlen(".res") );
201 20888 : if( aResName.isEmpty() )
202 0 : continue;
203 : assert( m_aResFiles.find( aResName ) == m_aResFiles.end() );
204 20888 : m_aResFiles[ aResName ].aFileURL = uri + aFileName;
205 : SAL_INFO(
206 : "tools.rc",
207 : "ResMgrContainer: " << aResName << " -> "
208 20888 : << m_aResFiles[ aResName ].aFileURL );
209 : }
210 21261 : }
211 : }
212 : else
213 : SAL_WARN( "tools.rc", "opening dir " << uri << " failed" );
214 :
215 : // set default language
216 373 : LanguageType nLang = MsLangId::getSystemUILanguage();
217 746 : m_aDefLocale.reset( nLang);
218 373 : }
219 :
220 : namespace
221 : {
222 4230 : bool isAlreadyPureenUS(const LanguageTag &rLocale)
223 : {
224 4230 : return ( rLocale.getLanguageType() == LANGUAGE_ENGLISH_US );
225 : }
226 : }
227 :
228 4230 : InternalResMgr* ResMgrContainer::getResMgr( const OUString& rPrefix,
229 : LanguageTag& rLocale,
230 : bool bForceNewInstance
231 : )
232 : {
233 4230 : LanguageTag aLocale( rLocale );
234 4230 : boost::unordered_map< OUString, ContainerElement, OUStringHash >::iterator it = m_aResFiles.end();
235 :
236 8460 : ::std::vector< OUString > aFallbacks( aLocale.getFallbackStrings( true));
237 4230 : if (!isAlreadyPureenUS( aLocale))
238 0 : aFallbacks.push_back( "en-US"); // last resort if all fallbacks fail
239 :
240 4230 : for (::std::vector< OUString >::const_iterator fb( aFallbacks.begin()); fb != aFallbacks.end(); ++fb)
241 : {
242 4230 : OUString aSearch( rPrefix + *fb );
243 4230 : it = m_aResFiles.find( aSearch );
244 4230 : if( it != m_aResFiles.end() )
245 : {
246 : // ensure InternalResMgr existence
247 4230 : if( ! it->second.pResMgr )
248 : {
249 : InternalResMgr* pImp =
250 2939 : new InternalResMgr( it->second.aFileURL, rPrefix, it->first, aLocale );
251 2939 : if( ! pImp->Create() )
252 : {
253 0 : delete pImp;
254 0 : continue;
255 : }
256 2939 : it->second.pResMgr = pImp;
257 : }
258 4230 : break;
259 : }
260 0 : }
261 : // try if there is anything with this prefix at all
262 4230 : 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 existence
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 4230 : 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 4230 : 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 4230 : InternalResMgr* pImp = it->second.pResMgr;
317 :
318 4230 : if( it->second.nRefCount == 0 )
319 2939 : it->second.nLoadCount++;
320 :
321 : // for SimpleResMgr
322 4230 : if( bForceNewInstance )
323 : {
324 15 : 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 15 : it->second.pResMgr = NULL;
329 15 : 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 4215 : it->second.nRefCount++;
346 :
347 8460 : 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 2221 : void ResMgrContainer::freeResMgr( InternalResMgr* pResMgr )
376 : {
377 2221 : if( pResMgr->bSingular )
378 0 : delete pResMgr;
379 : else
380 : {
381 : boost::unordered_map< OUString, ContainerElement, OUStringHash >::iterator it =
382 2221 : m_aResFiles.find( pResMgr->aResName );
383 2221 : if( it != m_aResFiles.end() )
384 : {
385 : DBG_ASSERT( it->second.nRefCount > 0, "InternalResMgr freed too often" );
386 2221 : if( it->second.nRefCount > 0 )
387 2221 : it->second.nRefCount--;
388 2221 : if( it->second.nRefCount == 0 )
389 : {
390 1429 : delete it->second.pResMgr;
391 1429 : it->second.pResMgr = NULL;
392 : }
393 : }
394 : }
395 2221 : }
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 16885968 : inline bool operator() (const ImpContent& lhs, const ImpContent& rhs) const
414 : {
415 16885968 : return lhs.nTypeAndId < rhs.nTypeAndId;
416 : }
417 : };
418 :
419 : static ResHookProc pImplResHookProc = 0;
420 :
421 2939 : 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 2939 : , pResUseDump( 0 )
437 : {
438 2939 : }
439 :
440 5790 : InternalResMgr::~InternalResMgr()
441 : {
442 2895 : rtl_freeMemory(pContent);
443 2895 : rtl_freeMemory(pStringBlock);
444 2895 : 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 2895 : delete pResUseDump;
474 2895 : }
475 :
476 2939 : bool InternalResMgr::Create()
477 : {
478 2939 : ResMgrContainer::get();
479 2939 : bool bDone = false;
480 :
481 2939 : pStm = new SvFileStream( aFileName, (STREAM_READ | STREAM_SHARE_DENYWRITE | STREAM_NOCREATE) );
482 2939 : if( pStm->GetError() == 0 )
483 : {
484 2939 : sal_Int32 lContLen = 0;
485 :
486 2939 : 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 2939 : pStm->SeekRel( - (int)sizeof( lContLen ) );
493 2939 : pStm->Read( &lContLen, sizeof( lContLen ) );
494 : // is bigendian, swab to the right endian
495 2939 : lContLen = ResMgr::GetLong( &lContLen );
496 2939 : pStm->SeekRel( -lContLen );
497 : // allocate stored ImpContent data (12 bytes per unit)
498 2939 : sal_uInt8* pContentBuf = (sal_uInt8*)rtl_allocateMemory( lContLen );
499 2939 : pStm->Read( pContentBuf, lContLen );
500 : // allocate ImpContent space (sizeof(ImpContent) per unit, not necessarily 12)
501 2939 : pContent = (ImpContent *)rtl_allocateMemory( sizeof(ImpContent)*lContLen/12 );
502 : // Shorten to number of ImpContent
503 2939 : nEntries = (sal_uInt32)lContLen / 12;
504 2939 : bEqual2Content = true;
505 2939 : bool bSorted = true;
506 2939 : 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 2939 : pContent[0].nTypeAndId = ResMgr::GetUInt64( pContentBuf );
519 2939 : pContent[0].nOffset = ResMgr::GetLong( pContentBuf+8 );
520 2939 : sal_uInt32 nCount = nEntries - 1;
521 803627 : for( sal_uInt32 i = 0,j=1; i < nCount; ++i,++j )
522 : {
523 : // swap the content to the right endian
524 800688 : pContent[j].nTypeAndId = ResMgr::GetUInt64( pContentBuf + (12*j) );
525 800688 : pContent[j].nOffset = ResMgr::GetLong( pContentBuf + (12*j+8) );
526 800688 : if( pContent[i].nTypeAndId >= pContent[j].nTypeAndId )
527 0 : bSorted = false;
528 800688 : if( (pContent[i].nTypeAndId & 0xFFFFFFFF00000000LL) == (pContent[j].nTypeAndId & 0xFFFFFFFF00000000LL)
529 783433 : && pContent[i].nOffset >= pContent[j].nOffset )
530 0 : bEqual2Content = false;
531 : }
532 : }
533 2939 : rtl_freeMemory( pContentBuf );
534 : OSL_ENSURE( bSorted, "content not sorted" );
535 : OSL_ENSURE( bEqual2Content, "resource structure wrong" );
536 2939 : if( !bSorted )
537 0 : ::std::sort(pContent,pContent+nEntries,ImpContentLessCompare());
538 : // qsort( pContent, nEntries, sizeof( ImpContent ), Compare );
539 :
540 2939 : bDone = true;
541 : }
542 :
543 2939 : return bDone;
544 : }
545 :
546 :
547 18970 : bool InternalResMgr::IsGlobalAvailable( RESOURCE_TYPE nRT, sal_uInt32 nId ) const
548 : {
549 : // Anfang der Strings suchen
550 : ImpContent aValue;
551 18970 : aValue.nTypeAndId = ((sal_uInt64(nRT) << 32) | nId);
552 : ImpContent * pFind = ::std::lower_bound(pContent,
553 : pContent + nEntries,
554 : aValue,
555 18970 : ImpContentLessCompare());
556 18970 : return (pFind != (pContent + nEntries)) && (pFind->nTypeAndId == aValue.nTypeAndId);
557 : }
558 :
559 :
560 1691387 : 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 1691387 : aValue.nTypeAndId = ((sal_uInt64(nRT) << 32) | nId);
570 1691387 : ImpContent* pEnd = (pContent + nEntries);
571 : ImpContent* pFind = ::std::lower_bound( pContent,
572 : pEnd,
573 : aValue,
574 1691387 : ImpContentLessCompare());
575 1691387 : if( pFind && (pFind != pEnd) && (pFind->nTypeAndId == aValue.nTypeAndId) )
576 : {
577 1691387 : if( nRT == RSC_STRING && bEqual2Content )
578 : {
579 : // string optimization
580 1589931 : if( !pStringBlock )
581 : {
582 : // search beginning of string
583 1912 : ImpContent * pFirst = pFind;
584 1912 : ImpContent * pLast = pFirst;
585 350928 : while( pFirst > pContent && ((pFirst -1)->nTypeAndId >> 32) == RSC_STRING )
586 347104 : --pFirst;
587 295759 : while( pLast < pEnd && (pLast->nTypeAndId >> 32) == RSC_STRING )
588 291935 : ++pLast;
589 1912 : nOffCorrection = pFirst->nOffset;
590 : sal_uInt32 nSize;
591 1912 : --pLast;
592 1912 : pStm->Seek( pLast->nOffset );
593 : RSHEADER_TYPE aHdr;
594 1912 : pStm->Read( &aHdr, sizeof( aHdr ) );
595 1912 : nSize = pLast->nOffset + aHdr.GetGlobOff() - nOffCorrection;
596 1912 : pStringBlock = (sal_uInt8*)rtl_allocateMemory( nSize );
597 1912 : pStm->Seek( pFirst->nOffset );
598 1912 : pStm->Read( pStringBlock, nSize );
599 : }
600 1589931 : *pResHandle = pStringBlock;
601 1589931 : return (sal_uInt8*)pStringBlock + pFind->nOffset - nOffCorrection;
602 : } // if( nRT == RSC_STRING && bEqual2Content )
603 : else
604 : {
605 101456 : *pResHandle = 0;
606 : RSHEADER_TYPE aHeader;
607 101456 : pStm->Seek( pFind->nOffset );
608 101456 : pStm->Read( &aHeader, sizeof( RSHEADER_TYPE ) );
609 101456 : void * pRes = rtl_allocateMemory( aHeader.GetGlobOff() );
610 101456 : memcpy( pRes, &aHeader, sizeof( RSHEADER_TYPE ) );
611 101456 : pStm->Read( (sal_uInt8*)pRes + sizeof( RSHEADER_TYPE ),
612 202912 : aHeader.GetGlobOff() - sizeof( RSHEADER_TYPE ) );
613 101456 : return pRes;
614 : }
615 : } // if( pFind && (pFind != pEnd) && (pFind->nTypeAndId == nValue) )
616 0 : *pResHandle = 0;
617 0 : return NULL;
618 : }
619 :
620 1691387 : void InternalResMgr::FreeGlobalRes( void * pResHandle, void * pResource )
621 : {
622 1691387 : if ( !pResHandle )
623 : // Free allocated resource
624 101456 : rtl_freeMemory(pResource);
625 1691387 : }
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 1897605 : void ImpRCStack::Init( ResMgr* pMgr, const Resource* pObj, sal_uInt32 Id )
726 : {
727 1897605 : pResource = NULL;
728 1897605 : pClassRes = NULL;
729 1897605 : Flags = RC_NOTYPE;
730 1897605 : aResHandle = NULL;
731 1897605 : pResObj = pObj;
732 1897605 : nId = Id & ~RSC_DONTRELEASE; //TLX: Besser Init aendern
733 1897605 : pResMgr = pMgr;
734 1897605 : if ( !(Id & RSC_DONTRELEASE) )
735 1897605 : Flags |= RC_AUTORELEASE;
736 1897605 : }
737 :
738 1901820 : void ImpRCStack::Clear()
739 : {
740 1901820 : pResource = NULL;
741 1901820 : pClassRes = NULL;
742 1901820 : Flags = RC_NOTYPE;
743 1901820 : aResHandle = NULL;
744 1901820 : pResObj = NULL;
745 1901820 : nId = 0;
746 1901820 : pResMgr = NULL;
747 1901820 : }
748 :
749 1920231 : 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 1920231 : if ( pStack->pResource && pStack->pClassRes )
758 : {
759 : pTmp = (RSHEADER_TYPE*)
760 226224 : ((sal_uInt8*)pStack->pResource + pStack->pResource->GetLocalOff());
761 : pEnd = (RSHEADER_TYPE*)
762 226224 : ((sal_uInt8*)pStack->pResource + pStack->pResource->GetGlobOff());
763 32741546 : while ( pTmp != pEnd )
764 : {
765 32499468 : if ( pTmp->GetRT() == nRTType && pTmp->GetId() == nId )
766 210370 : return pTmp;
767 32289098 : pTmp = (RSHEADER_TYPE*)((sal_uInt8*)pTmp + pTmp->GetGlobOff());
768 : }
769 : }
770 :
771 1709861 : 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 367 : void ResMgr::DestroyAllResMgr()
784 : {
785 : {
786 367 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
787 367 : if( pEmptyBuffer )
788 : {
789 0 : rtl_freeMemory( pEmptyBuffer );
790 0 : pEmptyBuffer = NULL;
791 : }
792 367 : ResMgrContainer::release();
793 : }
794 367 : delete pResMgrMutex;
795 367 : pResMgrMutex = NULL;
796 367 : }
797 :
798 4215 : void ResMgr::Init( const OUString& rFileName )
799 : {
800 : (void) rFileName; // avoid warning about unused parameter
801 4215 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
802 :
803 4215 : 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 4215 : nCurStack = -1;
829 4215 : aStack.clear();
830 4215 : pFallbackResMgr = pOriginalResMgr = NULL;
831 4215 : incStack();
832 4215 : }
833 :
834 4215 : ResMgr::ResMgr( InternalResMgr * pImpMgr )
835 : {
836 4215 : pImpRes = pImpMgr;
837 4215 : Init( pImpMgr->aFileName );
838 4215 : }
839 :
840 4442 : ResMgr::~ResMgr()
841 : {
842 2221 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
843 :
844 2221 : ResMgrContainer::get().freeResMgr( pImpRes );
845 :
846 : // clean up possible left rc stack frames
847 4442 : 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 2221 : }
854 2221 : }
855 :
856 1901820 : void ResMgr::incStack()
857 : {
858 1901820 : nCurStack++;
859 1901820 : if( nCurStack >= int(aStack.size()) )
860 7181 : aStack.push_back( ImpRCStack() );
861 1901820 : aStack[nCurStack].Clear();
862 :
863 : DBG_ASSERT( nCurStack < 32, "Resource stack unreasonably large" );
864 1901820 : }
865 :
866 1897605 : void ResMgr::decStack()
867 : {
868 : DBG_ASSERT( nCurStack > 0, "resource stack underrun !" );
869 1897605 : 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 1897605 : ImpRCStack& rTop = aStack[nCurStack];
878 1897605 : 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 1897605 : nCurStack--;
888 : }
889 1897605 : }
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 102552 : bool ResMgr::IsAvailable( const ResId& rId, const Resource* pResObj ) const
928 : {
929 102552 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
930 :
931 102552 : bool bAvailable = false;
932 102552 : RSHEADER_TYPE* pClassRes = rId.GetpResource();
933 102552 : RESOURCE_TYPE nRT = rId.GetRT2();
934 102552 : sal_uInt32 nId = rId.GetId();
935 102552 : const ResMgr* pMgr = rId.GetResMgr();
936 :
937 102552 : if ( !pMgr )
938 0 : pMgr = this;
939 :
940 102552 : 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 102552 : if ( !pResObj || pResObj == pMgr->aStack[pMgr->nCurStack].pResObj )
948 : {
949 102552 : if ( !pClassRes )
950 102552 : pClassRes = LocalResource( &pMgr->aStack[pMgr->nCurStack], nRT, nId );
951 102552 : if ( pClassRes )
952 : {
953 83628 : if ( pClassRes->GetRT() == nRT )
954 83628 : bAvailable = true;
955 : }
956 : }
957 :
958 102552 : if ( !pClassRes )
959 18924 : bAvailable = pMgr->pImpRes->IsGlobalAvailable( nRT, nId );
960 :
961 102552 : return bAvailable;
962 : }
963 :
964 2463296 : void* ResMgr::GetClass()
965 : {
966 2463296 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
967 :
968 2463296 : if( pFallbackResMgr )
969 0 : return pFallbackResMgr->GetClass();
970 :
971 2463296 : return aStack[nCurStack].pClassRes;
972 : }
973 :
974 1897605 : bool ResMgr::GetResource( const ResId& rId, const Resource* pResObj )
975 : {
976 1897605 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
977 :
978 1897605 : if( pFallbackResMgr )
979 : {
980 0 : ResId aId( rId );
981 0 : aId.SetResMgr( NULL );
982 0 : return pFallbackResMgr->GetResource( aId, pResObj );
983 : }
984 :
985 1897605 : ResMgr* pMgr = rId.GetResMgr();
986 1897605 : 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 1897605 : ImpRCStack* pTop = &aStack[nCurStack];
992 1897605 : if( (pTop->Flags & RC_NOTFOUND) )
993 : {
994 0 : decStack();
995 : }
996 :
997 1897605 : RSHEADER_TYPE* pClassRes = rId.GetpResource();
998 1897605 : RESOURCE_TYPE nRT = rId.GetRT2();
999 1897605 : sal_uInt32 nId = rId.GetId();
1000 :
1001 1897605 : incStack();
1002 1897605 : pTop = &aStack[nCurStack];
1003 : pTop->Init( pMgr, pResObj, nId |
1004 1897605 : (rId.IsAutoRelease() ? 0 : RSC_DONTRELEASE) );
1005 :
1006 1897605 : if ( pClassRes )
1007 : {
1008 79926 : if ( pClassRes->GetRT() == nRT )
1009 79926 : 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 1817679 : pTop->pClassRes = LocalResource( &aStack[nCurStack-1], nRT, nId );
1026 : }
1027 :
1028 1897605 : if ( pTop->pClassRes )
1029 : // local Resource, not a system Resource
1030 206668 : pTop->pResource = (RSHEADER_TYPE *)pTop->pClassRes;
1031 : else
1032 : {
1033 1690937 : pTop->pClassRes = pImpRes->LoadGlobalRes( nRT, nId, &pTop->aResHandle );
1034 1690937 : if ( pTop->pClassRes )
1035 : {
1036 1690937 : pTop->Flags |= RC_GLOBAL;
1037 1690937 : 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 1897605 : return true;
1073 : }
1074 :
1075 69010 : void * ResMgr::GetResourceSkipHeader( const ResId& rResId, ResMgr ** ppResMgr )
1076 : {
1077 69010 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1078 :
1079 : DBG_ASSERT( rResId.GetResMgr(), "illegal ResId without ResMgr" );
1080 69010 : *ppResMgr = rResId.GetResMgr();
1081 69010 : if( *ppResMgr )
1082 : {
1083 69010 : (*ppResMgr)->GetResource( rResId );
1084 69010 : (*ppResMgr)->Increment( sizeof( RSHEADER_TYPE ) );
1085 69010 : return (*ppResMgr)->GetClass();
1086 : }
1087 0 : return getEmptyBuffer();
1088 : }
1089 :
1090 1897605 : void ResMgr::PopContext( const Resource* pResObj )
1091 : {
1092 1897605 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1093 :
1094 1897605 : if( pFallbackResMgr )
1095 : {
1096 0 : pFallbackResMgr->PopContext( pResObj );
1097 1897605 : 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 1897605 : if ( nCurStack > 0 )
1112 : {
1113 1897605 : 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 1897605 : if( (pTop->Flags & (RC_GLOBAL | RC_NOTFOUND)) == RC_GLOBAL )
1132 : // free global resource if resource is foreign
1133 1690937 : InternalResMgr::FreeGlobalRes( pTop->aResHandle, pTop->pResource );
1134 1897605 : decStack();
1135 1897605 : }
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 19134 : sal_Int16 ResMgr::GetShort( void * pShort )
1167 : {
1168 19134 : return ((*((sal_uInt8*)pShort + 0) << 8) |
1169 19134 : (*((sal_uInt8*)pShort + 1) << 0) );
1170 : }
1171 :
1172 104363013 : sal_Int32 ResMgr::GetLong( void * pLong )
1173 : {
1174 208726026 : return ((*((sal_uInt8*)pLong + 0) << 24) |
1175 208726026 : (*((sal_uInt8*)pLong + 1) << 16) |
1176 104363013 : (*((sal_uInt8*)pLong + 2) << 8) |
1177 104363013 : (*((sal_uInt8*)pLong + 3) << 0) );
1178 : }
1179 :
1180 803627 : sal_uInt64 ResMgr::GetUInt64( void* pDatum )
1181 : {
1182 1607254 : return ((sal_uInt64(*((sal_uInt8*)pDatum + 0)) << 56) |
1183 1607254 : (sal_uInt64(*((sal_uInt8*)pDatum + 1)) << 48) |
1184 1607254 : (sal_uInt64(*((sal_uInt8*)pDatum + 2)) << 40) |
1185 1607254 : (sal_uInt64(*((sal_uInt8*)pDatum + 3)) << 32) |
1186 1607254 : (sal_uInt64(*((sal_uInt8*)pDatum + 4)) << 24) |
1187 1607254 : (sal_uInt64(*((sal_uInt8*)pDatum + 5)) << 16) |
1188 803627 : (sal_uInt64(*((sal_uInt8*)pDatum + 6)) << 8) |
1189 803627 : (sal_uInt64(*((sal_uInt8*)pDatum + 7)) << 0) );
1190 : }
1191 :
1192 122870 : sal_uInt32 ResMgr::GetStringWithoutHook( OUString& rStr, const sal_uInt8* pStr )
1193 : {
1194 122870 : sal_uInt32 nLen=0;
1195 122870 : sal_uInt32 nRet = GetStringSize( pStr, nLen );
1196 122870 : const sal_Char* str = reinterpret_cast< const sal_Char* >( pStr );
1197 122870 : OUString aString( str, strlen( str ), RTL_TEXTENCODING_UTF8,
1198 : RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_MAPTOPRIVATE |
1199 : RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT |
1200 122870 : RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT );
1201 122870 : rStr = aString;
1202 122870 : return nRet;
1203 : }
1204 :
1205 450 : sal_uInt32 ResMgr::GetString( OUString& rStr, const sal_uInt8* pStr )
1206 : {
1207 450 : OUString aString;
1208 450 : sal_uInt32 nRet = GetStringWithoutHook( aString, pStr );
1209 450 : if ( pImplResHookProc )
1210 440 : aString = pImplResHookProc( aString );
1211 450 : rStr = aString;
1212 450 : return nRet;
1213 : }
1214 :
1215 13996 : sal_uInt32 ResMgr::GetByteString( OString& rStr, const sal_uInt8* pStr )
1216 : {
1217 13996 : sal_uInt32 nLen=0;
1218 13996 : sal_uInt32 nRet = GetStringSize( pStr, nLen );
1219 13996 : rStr = OString( (const sal_Char*)pStr, nLen );
1220 13996 : return nRet;
1221 : }
1222 :
1223 136866 : sal_uInt32 ResMgr::GetStringSize( const sal_uInt8* pStr, sal_uInt32& nLen )
1224 : {
1225 136866 : nLen = static_cast< sal_uInt32 >( strlen( (const char*)pStr ) );
1226 136866 : 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 : return (sal_uInt32)(reinterpret_cast<sal_IntPtr>(rTop.pResource) +
1238 0 : rTop.pResource->GetLocalOff() -
1239 0 : reinterpret_cast<sal_IntPtr>(rTop.pClassRes));
1240 : }
1241 :
1242 2507486 : void* ResMgr::Increment( sal_uInt32 nSize )
1243 : {
1244 2507486 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1245 :
1246 2507486 : if( pFallbackResMgr )
1247 0 : return pFallbackResMgr->Increment( nSize );
1248 :
1249 2507486 : ImpRCStack& rStack = aStack[nCurStack];
1250 2507486 : if( (rStack.Flags & RC_NOTFOUND) )
1251 0 : return rStack.pClassRes;
1252 :
1253 2507486 : sal_uInt8* pClassRes = (sal_uInt8*)rStack.pClassRes + nSize;
1254 :
1255 2507486 : rStack.pClassRes = pClassRes;
1256 :
1257 2507486 : RSHEADER_TYPE* pRes = rStack.pResource;
1258 :
1259 2507486 : sal_uInt32 nLocalOff = pRes->GetLocalOff();
1260 7456672 : if ( (pRes->GetGlobOff() == nLocalOff) &&
1261 4362075 : (((char*)pRes + nLocalOff) == rStack.pClassRes) &&
1262 1854589 : (rStack.Flags & RC_AUTORELEASE))
1263 : {
1264 1854589 : PopContext( rStack.pResObj );
1265 : }
1266 :
1267 2507486 : 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 3789 : ResMgr* ResMgr::CreateResMgr( const sal_Char* pPrefixName,
1332 : const LanguageTag& _aLocale )
1333 : {
1334 3789 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1335 :
1336 7578 : OUString aPrefix( pPrefixName, strlen( pPrefixName ), osl_getThreadTextEncoding() );
1337 :
1338 7578 : LanguageTag aLocale = _aLocale;
1339 3789 : if( aLocale.isSystemLocale() )
1340 1460 : aLocale = ResMgrContainer::get().getDefLocale();
1341 :
1342 3789 : InternalResMgr* pImp = ResMgrContainer::get().getResMgr( aPrefix, aLocale );
1343 7578 : return pImp ? new ResMgr( pImp ) : NULL;
1344 : }
1345 :
1346 426 : ResMgr* ResMgr::SearchCreateResMgr(
1347 : const sal_Char* pPrefixName,
1348 : LanguageTag& rLocale )
1349 : {
1350 426 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1351 :
1352 852 : OUString aPrefix( pPrefixName, strlen( pPrefixName ), osl_getThreadTextEncoding() );
1353 :
1354 426 : if( rLocale.isSystemLocale() )
1355 160 : rLocale = ResMgrContainer::get().getDefLocale();
1356 :
1357 426 : InternalResMgr* pImp = ResMgrContainer::get().getResMgr( aPrefix, rLocale );
1358 852 : return pImp ? new ResMgr( pImp ) : NULL;
1359 : }
1360 :
1361 19134 : sal_Int16 ResMgr::ReadShort()
1362 : {
1363 19134 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1364 :
1365 19134 : if( pFallbackResMgr )
1366 0 : return pFallbackResMgr->ReadShort();
1367 :
1368 19134 : sal_Int16 n = GetShort( GetClass() );
1369 19134 : Increment( sizeof( sal_Int16 ) );
1370 19134 : return n;
1371 : }
1372 :
1373 352704 : sal_Int32 ResMgr::ReadLong()
1374 : {
1375 352704 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1376 :
1377 352704 : if( pFallbackResMgr )
1378 0 : return pFallbackResMgr->ReadLong();
1379 :
1380 352704 : sal_Int32 n = GetLong( GetClass() );
1381 352704 : Increment( sizeof( sal_Int32 ) );
1382 352704 : return n;
1383 : }
1384 :
1385 122420 : OUString ResMgr::ReadStringWithoutHook()
1386 : {
1387 122420 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1388 :
1389 122420 : if( pFallbackResMgr )
1390 0 : return pFallbackResMgr->ReadStringWithoutHook();
1391 :
1392 244840 : OUString aRet;
1393 :
1394 122420 : const ImpRCStack& rTop = aStack[nCurStack];
1395 122420 : if( (rTop.Flags & RC_NOTFOUND) )
1396 : {
1397 : #if OSL_DEBUG_LEVEL > 0
1398 : aRet = "<resource not found>";
1399 : #endif
1400 : }
1401 : else
1402 122420 : Increment( GetStringWithoutHook( aRet, (const sal_uInt8*)GetClass() ) );
1403 :
1404 244840 : return aRet;
1405 : }
1406 :
1407 122420 : OUString ResMgr::ReadString()
1408 : {
1409 122420 : OUString aRet = ReadStringWithoutHook();
1410 122420 : if ( pImplResHookProc )
1411 93015 : aRet = pImplResHookProc( aRet );
1412 122420 : return aRet;
1413 : }
1414 :
1415 13996 : OString ResMgr::ReadByteString()
1416 : {
1417 13996 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1418 :
1419 13996 : if( pFallbackResMgr )
1420 0 : return pFallbackResMgr->ReadByteString();
1421 :
1422 27992 : OString aRet;
1423 :
1424 13996 : const ImpRCStack& rTop = aStack[nCurStack];
1425 13996 : if( (rTop.Flags & RC_NOTFOUND) )
1426 : {
1427 : #if OSL_DEBUG_LEVEL > 0
1428 : aRet = OString( "<resource not found>" );
1429 : #endif
1430 : }
1431 : else
1432 13996 : Increment( GetByteString( aRet, (const sal_uInt8*)GetClass() ) );
1433 :
1434 27992 : return aRet;
1435 : }
1436 :
1437 10002 : OString ResMgr::GetAutoHelpId()
1438 : {
1439 10002 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1440 :
1441 10002 : if( pFallbackResMgr )
1442 0 : return pFallbackResMgr->GetAutoHelpId();
1443 :
1444 : OSL_ENSURE( nCurStack, "resource stack empty in Auto help id generation" );
1445 10002 : if( nCurStack < 1 || nCurStack > 2 )
1446 0 : return OString();
1447 :
1448 : // prepare HID, start with resource prefix
1449 20004 : OStringBuffer aHID( 32 );
1450 10002 : aHID.append( OUStringToOString( pImpRes->aPrefix, RTL_TEXTENCODING_UTF8 ) );
1451 10002 : aHID.append( '.' );
1452 :
1453 : // append type
1454 10002 : const ImpRCStack *pRC = StackTop();
1455 : OSL_ENSURE( pRC, "missing resource stack level" );
1456 :
1457 10002 : if ( nCurStack == 1 )
1458 : {
1459 : // auto help ids for top level windows
1460 5530 : switch( pRC->pResource->GetRT() ) {
1461 202 : case RSC_DOCKINGWINDOW: aHID.append( "DockingWindow" ); break;
1462 0 : case RSC_WORKWIN: aHID.append( "WorkWindow" ); break;
1463 5328 : default: return OString();
1464 : }
1465 : }
1466 : else
1467 : {
1468 : // only controls with the following parents get auto help ids
1469 4472 : const ImpRCStack *pRC1 = StackTop(1);
1470 4472 : switch( pRC1->pResource->GetRT() ) {
1471 : case RSC_DOCKINGWINDOW:
1472 : case RSC_WORKWIN:
1473 : // intentionally no breaks!
1474 : // auto help ids for controls
1475 68 : switch( pRC->pResource->GetRT() ) {
1476 0 : case RSC_RADIOBUTTON: aHID.append( "RadioButton" ); break;
1477 0 : case RSC_CHECKBOX: aHID.append( "CheckBox" ); break;
1478 0 : case RSC_EDIT: aHID.append( "Edit" ); break;
1479 34 : case RSC_LISTBOX: aHID.append( "ListBox" ); break;
1480 0 : case RSC_COMBOBOX: aHID.append( "ComboBox" ); break;
1481 0 : case RSC_PUSHBUTTON: aHID.append( "PushButton" ); break;
1482 0 : case RSC_SPINFIELD: aHID.append( "SpinField" ); break;
1483 0 : case RSC_NUMERICFIELD: aHID.append( "NumericField" ); break;
1484 0 : case RSC_METRICFIELD: aHID.append( "MetricField" ); break;
1485 0 : case RSC_DATEFIELD: aHID.append( "DateField" ); break;
1486 0 : case RSC_TIMEFIELD: aHID.append( "TimeField" ); break;
1487 0 : case RSC_IMAGEBUTTON: aHID.append( "ImageButton" ); break;
1488 : default:
1489 : // no type, no auto HID
1490 34 : return OString();
1491 : }
1492 34 : break;
1493 : default:
1494 4404 : return OString();
1495 : }
1496 : }
1497 :
1498 : // append resource id hierarchy
1499 506 : for( int nOff = nCurStack-1; nOff >= 0; nOff-- )
1500 : {
1501 270 : aHID.append( '.' );
1502 270 : pRC = StackTop( nOff );
1503 :
1504 : OSL_ENSURE( pRC->pResource, "missing resource in resource stack level !" );
1505 270 : if( pRC->pResource )
1506 270 : aHID.append( sal_Int32( pRC->pResource->GetId() ) );
1507 : }
1508 :
1509 10238 : return aHID.makeStringAndClear();
1510 : }
1511 :
1512 160 : void ResMgr::SetReadStringHook( ResHookProc pProc )
1513 : {
1514 160 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1515 160 : pImplResHookProc = pProc;
1516 160 : }
1517 :
1518 1694111 : ResHookProc ResMgr::GetReadStringHook()
1519 : {
1520 1694111 : return pImplResHookProc;
1521 : }
1522 :
1523 1389 : void ResMgr::SetDefaultLocale( const LanguageTag& rLocale )
1524 : {
1525 1389 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1526 1389 : ResMgrContainer::get().setDefLocale( rLocale );
1527 1389 : }
1528 :
1529 0 : const OUString& ResMgr::GetFileName() const
1530 : {
1531 0 : return pImpRes->aFileName;
1532 : }
1533 :
1534 15 : SimpleResMgr::SimpleResMgr( const sal_Char* pPrefixName,
1535 15 : const LanguageTag& rLocale )
1536 : {
1537 15 : OUString aPrefix( pPrefixName, strlen( pPrefixName ), osl_getThreadTextEncoding() );
1538 30 : LanguageTag aLocale( rLocale );
1539 :
1540 30 : osl::Guard<osl::Mutex> aGuard( getResMgrMutex() );
1541 15 : if( aLocale.isSystemLocale() )
1542 0 : aLocale = ResMgrContainer::get().getDefLocale();
1543 :
1544 15 : m_pResImpl = ResMgrContainer::get().getResMgr( aPrefix, aLocale, true );
1545 15 : DBG_ASSERT( m_pResImpl, "SimpleResMgr::SimpleResMgr : have no impl class !" );
1546 15 : }
1547 :
1548 45 : SimpleResMgr::~SimpleResMgr()
1549 : {
1550 15 : delete m_pResImpl;
1551 30 : }
1552 :
1553 10 : SimpleResMgr* SimpleResMgr::Create( const sal_Char* pPrefixName, LanguageTag aLocale )
1554 : {
1555 10 : return new SimpleResMgr( pPrefixName, aLocale );
1556 : }
1557 :
1558 46 : bool SimpleResMgr::IsAvailable( RESOURCE_TYPE _resourceType, sal_uInt32 _resourceId )
1559 : {
1560 46 : osl::MutexGuard aGuard(m_aAccessSafety);
1561 :
1562 46 : if ( ( RSC_STRING != _resourceType ) && ( RSC_RESOURCE != _resourceType ) )
1563 0 : return false;
1564 :
1565 : DBG_ASSERT( m_pResImpl, "SimpleResMgr::IsAvailable: have no impl class !" );
1566 46 : return m_pResImpl->IsGlobalAvailable( _resourceType, _resourceId );
1567 : }
1568 :
1569 450 : OUString SimpleResMgr::ReadString( sal_uInt32 nId )
1570 : {
1571 450 : osl::MutexGuard aGuard(m_aAccessSafety);
1572 :
1573 : DBG_ASSERT( m_pResImpl, "SimpleResMgr::ReadString : have no impl class !" );
1574 : // perhaps constructed with an invalid filename ?
1575 :
1576 450 : OUString sReturn;
1577 450 : if ( !m_pResImpl )
1578 0 : return sReturn;
1579 :
1580 450 : void* pResHandle = NULL;
1581 450 : InternalResMgr* pFallback = m_pResImpl;
1582 450 : RSHEADER_TYPE* pResHeader = (RSHEADER_TYPE*)m_pResImpl->LoadGlobalRes( RSC_STRING, nId, &pResHandle );
1583 450 : if ( !pResHeader )
1584 : {
1585 0 : osl::Guard<osl::Mutex> aGuard2( getResMgrMutex() );
1586 :
1587 : // try fallback
1588 0 : while( ! pResHandle && pFallback )
1589 : {
1590 0 : InternalResMgr* pOldFallback = pFallback;
1591 0 : pFallback = ResMgrContainer::get().getNextFallback( pFallback );
1592 0 : if( pOldFallback != m_pResImpl )
1593 0 : ResMgrContainer::get().freeResMgr( pOldFallback );
1594 0 : if( pFallback )
1595 : {
1596 : // handle possible recursion
1597 0 : if( pFallback->aLocale != m_pResImpl->aLocale )
1598 : {
1599 0 : pResHeader = (RSHEADER_TYPE*)pFallback->LoadGlobalRes( RSC_STRING, nId, &pResHandle );
1600 : }
1601 : else
1602 : {
1603 0 : ResMgrContainer::get().freeResMgr( pFallback );
1604 0 : pFallback = NULL;
1605 : }
1606 : }
1607 : }
1608 0 : if( ! pResHandle )
1609 : // no such resource
1610 0 : return sReturn;
1611 : }
1612 :
1613 : // sal_uIntPtr nLen = pResHeader->GetLocalOff() - sizeof(RSHEADER_TYPE);
1614 450 : ResMgr::GetString( sReturn, (const sal_uInt8*)(pResHeader+1) );
1615 :
1616 : // not necessary with the current implementation which holds the string table permanently, but to be sure ....
1617 : // note: pFallback cannot be NULL here and is either the fallback or m_pResImpl
1618 450 : InternalResMgr::FreeGlobalRes( pResHeader, pResHandle );
1619 450 : if( m_pResImpl != pFallback )
1620 : {
1621 0 : osl::Guard<osl::Mutex> aGuard2( getResMgrMutex() );
1622 :
1623 0 : ResMgrContainer::get().freeResMgr( pFallback );
1624 : }
1625 450 : return sReturn;
1626 : }
1627 :
1628 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|