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