1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_extensions.hxx"
26 
27 #ifndef EXTENSIONS_SOURCE_RESOURCE_OOORESOURCELOADER_CXX
28 #define EXTENSIONS_SOURCE_RESOURCE_OOORESOURCELOADER_CXX
29 #include "res_services.hxx"
30 
31 /** === begin UNO includes === **/
32 #include <com/sun/star/resource/XResourceBundleLoader.hpp>
33 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
34 #include <com/sun/star/uno/XComponentContext.hpp>
35 /** === end UNO includes === **/
36 #include <vcl/svapp.hxx>
37 #include <tools/simplerm.hxx>
38 #include <tools/rcid.h>
39 #include <cppuhelper/implbase1.hxx>
40 #include <cppuhelper/weakref.hxx>
41 
42 #include <boost/shared_ptr.hpp>
43 #include <map>
44 
45 //........................................................................
46 namespace res
47 {
48 //........................................................................
49 
50     /** === begin UNO using === **/
51     using ::com::sun::star::uno::Reference;
52     using ::com::sun::star::resource::XResourceBundleLoader;
53     using ::com::sun::star::resource::XResourceBundle;
54     using ::com::sun::star::resource::MissingResourceException;
55     using ::com::sun::star::uno::XComponentContext;
56     using ::com::sun::star::uno::Sequence;
57     using ::com::sun::star::uno::XInterface;
58     using ::com::sun::star::uno::RuntimeException;
59     using ::com::sun::star::lang::Locale;
60     using ::com::sun::star::uno::Any;
61     using ::com::sun::star::container::NoSuchElementException;
62     using ::com::sun::star::lang::WrappedTargetException;
63     using ::com::sun::star::uno::Type;
64     using ::com::sun::star::uno::WeakReference;
65     /** === end UNO using === **/
66 
67 	//====================================================================
68 	//= helper
69 	//====================================================================
70     typedef ::std::pair< ::rtl::OUString, Locale >  ResourceBundleDescriptor;
71 
72     struct ResourceBundleDescriptorLess : public ::std::binary_function< ResourceBundleDescriptor, ResourceBundleDescriptor, bool >
73     {
operator ()res::ResourceBundleDescriptorLess74         bool operator()( const ResourceBundleDescriptor& _lhs, const ResourceBundleDescriptor& _rhs ) const
75         {
76             if ( _lhs.first < _rhs.first )
77                 return true;
78             if ( _lhs.second.Language < _rhs.second.Language )
79                 return true;
80             if ( _lhs.second.Country < _rhs.second.Country )
81                 return true;
82             if ( _lhs.second.Variant < _rhs.second.Variant )
83                 return true;
84             return false;
85         }
86     };
87 
88 	//====================================================================
89 	//= OpenOfficeResourceLoader
90 	//====================================================================
91     typedef ::cppu::WeakImplHelper1 <   XResourceBundleLoader
92                                     >   OpenOfficeResourceLoader_Base;
93     class OpenOfficeResourceLoader : public OpenOfficeResourceLoader_Base
94 	{
95     private:
96         typedef ::std::map< ResourceBundleDescriptor, WeakReference< XResourceBundle >, ResourceBundleDescriptorLess >
97                                         ResourceBundleCache;
98 
99     private:
100         Reference< XComponentContext >  m_xContext;
101         ::osl::Mutex                    m_aMutex;
102         ResourceBundleCache             m_aBundleCache;
103 
104     protected:
105         OpenOfficeResourceLoader( const Reference< XComponentContext >& _rxContext );
106 
107     public:
108         static Sequence< ::rtl::OUString > getSupportedServiceNames_static();
109         static ::rtl::OUString  getImplementationName_static();
110         static ::rtl::OUString  getSingletonName_static();
111         static Reference< XInterface > Create( const Reference< XComponentContext >& _rxContext );
112 
113         // XResourceBundleLoader
114         virtual Reference< XResourceBundle > SAL_CALL loadBundle_Default( const ::rtl::OUString& aBaseName ) throw (MissingResourceException, RuntimeException);
115         virtual Reference< XResourceBundle > SAL_CALL loadBundle( const ::rtl::OUString& abaseName, const Locale& aLocale ) throw (MissingResourceException, RuntimeException);
116 
117     private:
118         OpenOfficeResourceLoader();                                             // never implemented
119         OpenOfficeResourceLoader( const OpenOfficeResourceLoader& );            // never implemented
120         OpenOfficeResourceLoader& operator=( const OpenOfficeResourceLoader& ); // never implemented
121 	};
122 
123 	//====================================================================
124 	//= IResourceType
125 	//====================================================================
126     /** encapsulates access to a fixed resource type
127     */
128     class IResourceType
129     {
130     public:
131         /** returns the RESOURCE_TYPE associated with this instance
132         */
133         virtual RESOURCE_TYPE getResourceType() const = 0;
134 
135         /** reads a single resource from the given resource manager
136             @param  _resourceManager
137                 the resource manager to read from
138             @param  _resourceId
139                 the id of the resource to read
140             @return
141                 the required resource
142             @precond
143                 the caler checked via <code>_resourceManager.IsAvailable( getResourceType(), _resourceId )</code>
144                 that the required resource really exists
145         */
146         virtual Any getResource( SimpleResMgr& _resourceManager, sal_Int32 _resourceId ) const = 0;
147 
~IResourceType()148         virtual ~IResourceType() { };
149     };
150 
151 	//====================================================================
152 	//= StringResourceAccess
153 	//====================================================================
154     class StringResourceAccess : public IResourceType
155     {
156     public:
157         StringResourceAccess();
158 
159         // IResourceType
160         virtual RESOURCE_TYPE getResourceType() const;
161         virtual Any getResource( SimpleResMgr& _resourceManager, sal_Int32 _resourceId ) const;
162     };
163 
164     //--------------------------------------------------------------------
StringResourceAccess()165     StringResourceAccess::StringResourceAccess()
166     {
167     }
168 
169     //--------------------------------------------------------------------
getResourceType() const170     RESOURCE_TYPE StringResourceAccess::getResourceType() const
171     {
172         return RSC_STRING;
173     }
174 
175     //--------------------------------------------------------------------
getResource(SimpleResMgr & _resourceManager,sal_Int32 _resourceId) const176     Any StringResourceAccess::getResource( SimpleResMgr& _resourceManager, sal_Int32 _resourceId ) const
177     {
178         OSL_PRECOND( _resourceManager.IsAvailable( getResourceType(), _resourceId ), "StringResourceAccess::getResource: precondition not met!" );
179         Any aResource;
180         aResource <<= ::rtl::OUString( _resourceManager.ReadString( _resourceId ) );
181         return aResource;
182     }
183 
184     //====================================================================
185 	//= OpenOfficeResourceBundle
186 	//====================================================================
187     typedef ::cppu::WeakImplHelper1 <   XResourceBundle
188                                     >   OpenOfficeResourceBundle_Base;
189     class OpenOfficeResourceBundle : public OpenOfficeResourceBundle_Base
190     {
191     private:
192         typedef ::boost::shared_ptr< IResourceType >            ResourceTypePtr;
193         typedef ::std::map< ::rtl::OUString, ResourceTypePtr >  ResourceTypes;
194 
195         ::osl::Mutex                    m_aMutex;
196         Reference< XResourceBundle >    m_xParent;
197         Locale                          m_aLocale;
198         SimpleResMgr*                   m_pResourceManager;
199         ResourceTypes                   m_aResourceTypes;
200 
201     public:
202         OpenOfficeResourceBundle(
203             const Reference< XComponentContext >& _rxContext,
204             const ::rtl::OUString& _rBaseName,
205             const Locale& _rLocale
206         );
207 
208     protected:
209         ~OpenOfficeResourceBundle();
210 
211     public:
212         // XResourceBundle
213         virtual ::com::sun::star::uno::Reference< ::com::sun::star::resource::XResourceBundle > SAL_CALL getParent() throw (::com::sun::star::uno::RuntimeException);
214         virtual void SAL_CALL setParent( const ::com::sun::star::uno::Reference< ::com::sun::star::resource::XResourceBundle >& _parent ) throw (::com::sun::star::uno::RuntimeException);
215         virtual ::com::sun::star::lang::Locale SAL_CALL getLocale(  ) throw (::com::sun::star::uno::RuntimeException);
216         virtual ::com::sun::star::uno::Any SAL_CALL getDirectElement( const ::rtl::OUString& key ) throw (::com::sun::star::uno::RuntimeException);
217 
218         // XNameAccess (base of XResourceBundle)
219         virtual ::com::sun::star::uno::Any SAL_CALL getByName( const ::rtl::OUString& aName ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
220         virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getElementNames(  ) throw (::com::sun::star::uno::RuntimeException);
221         virtual ::sal_Bool SAL_CALL hasByName( const ::rtl::OUString& aName ) throw (::com::sun::star::uno::RuntimeException);
222 
223         // XElementAccess (base of XNameAccess)
224         virtual ::com::sun::star::uno::Type SAL_CALL getElementType(  ) throw (::com::sun::star::uno::RuntimeException);
225         virtual ::sal_Bool SAL_CALL hasElements(  ) throw (::com::sun::star::uno::RuntimeException);
226 
227     private:
228         /** retrievs the element with the given key, without asking our parent bundle
229             @param  _key
230                 the key of the element to retrieve
231             @param  _out_Element
232                 will contained the retrieved element upon successful return. If the method is unsuccessful, the
233                 value will not be touched.
234             @return
235                 <TRUE/> if and only if the element could be retrieved
236             @precond
237                 our mutex is locked
238         */
239         bool    impl_getDirectElement_nothrow( const ::rtl::OUString& _key, Any& _out_Element ) const;
240 
241         /** retrieves the resource type and id from a given resource key, which assembles those two
242             @param  _key
243                 the resource key as got via a public API call
244             @param  _out_resourceType
245                 the resource type, if successful
246             @param  _out_resourceId
247                 the resource id, if successful
248             @return
249                 <TRUE/> if and only if the given key specifies a known resource type, and contains a valid
250                 resource id
251         */
252         bool    impl_getResourceTypeAndId_nothrow( const ::rtl::OUString& _key, ResourceTypePtr& _out_resourceType, sal_Int32& _out_resourceId ) const;
253     };
254 
255 	//====================================================================
256 	//= OpenOfficeResourceLoader
257 	//====================================================================
258 	//--------------------------------------------------------------------
OpenOfficeResourceLoader(const Reference<XComponentContext> & _rxContext)259     OpenOfficeResourceLoader::OpenOfficeResourceLoader( const Reference< XComponentContext >& _rxContext )
260         :m_xContext( _rxContext )
261     {
262     }
263 
264 	//--------------------------------------------------------------------
getSupportedServiceNames_static()265     Sequence< ::rtl::OUString > OpenOfficeResourceLoader::getSupportedServiceNames_static()
266     {
267         Sequence< ::rtl::OUString > aServices( 1 );
268         aServices[ 0 ] = getSingletonName_static();
269         return aServices;
270     }
271 
272 	//--------------------------------------------------------------------
getImplementationName_static()273     ::rtl::OUString OpenOfficeResourceLoader::getImplementationName_static()
274     {
275         return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.resource.OpenOfficeResourceLoader" ) );
276     }
277 
278 	//--------------------------------------------------------------------
getSingletonName_static()279     ::rtl::OUString OpenOfficeResourceLoader::getSingletonName_static()
280     {
281         return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.resource.OfficeResourceLoader" ) );
282     }
283 
284 	//--------------------------------------------------------------------
Create(const Reference<XComponentContext> & _rxContext)285     Reference< XInterface > OpenOfficeResourceLoader::Create( const Reference< XComponentContext >& _rxContext )
286     {
287         return *( new OpenOfficeResourceLoader( _rxContext ) );
288     }
289 
290     //--------------------------------------------------------------------
loadBundle_Default(const::rtl::OUString & _baseName)291     Reference< XResourceBundle > SAL_CALL OpenOfficeResourceLoader::loadBundle_Default( const ::rtl::OUString& _baseName ) throw (MissingResourceException, RuntimeException)
292     {
293         return loadBundle( _baseName, Application::GetSettings().GetUILocale() );
294     }
295 
296     //--------------------------------------------------------------------
loadBundle(const::rtl::OUString & _baseName,const Locale & _locale)297     Reference< XResourceBundle > SAL_CALL OpenOfficeResourceLoader::loadBundle( const ::rtl::OUString& _baseName, const Locale& _locale ) throw (MissingResourceException, RuntimeException)
298     {
299         ::osl::MutexGuard aGuard( m_aMutex );
300 
301         Reference< XResourceBundle > xBundle;
302 
303         ResourceBundleDescriptor resourceDescriptor( _baseName, _locale );
304         ResourceBundleCache::iterator cachePos = m_aBundleCache.find( resourceDescriptor );
305         if ( cachePos != m_aBundleCache.end() )
306             xBundle = cachePos->second;
307 
308         if ( !xBundle.is() )
309         {   // not in the cache, or already died
310             xBundle = new OpenOfficeResourceBundle( m_xContext, _baseName, _locale );
311             m_aBundleCache.insert( ResourceBundleCache::value_type( resourceDescriptor, xBundle ) );
312         }
313 
314         return xBundle;
315     }
316 
317     //--------------------------------------------------------------------
getComponentInfo_OpenOfficeResourceLoader()318     ComponentInfo getComponentInfo_OpenOfficeResourceLoader()
319     {
320         ComponentInfo aInfo;
321         aInfo.aSupportedServices = OpenOfficeResourceLoader::getSupportedServiceNames_static();
322         aInfo.sImplementationName = OpenOfficeResourceLoader::getImplementationName_static();
323         aInfo.sSingletonName = OpenOfficeResourceLoader::getSingletonName_static();
324         aInfo.pFactory = &OpenOfficeResourceLoader::Create;
325         return aInfo;
326     }
327 
328 	//====================================================================
329 	//= OpenOfficeResourceBundle
330 	//====================================================================
331     //--------------------------------------------------------------------
OpenOfficeResourceBundle(const Reference<XComponentContext> &,const::rtl::OUString & _rBaseName,const Locale & _rLocale)332     OpenOfficeResourceBundle::OpenOfficeResourceBundle( const Reference< XComponentContext >& /*_rxContext*/, const ::rtl::OUString& _rBaseName, const Locale& _rLocale )
333         :m_aLocale( _rLocale )
334         ,m_pResourceManager( NULL )
335     {
336         ::rtl::OUString sBaseName( _rBaseName );
337         m_pResourceManager = new SimpleResMgr( sBaseName, m_aLocale );
338 
339         if ( !m_pResourceManager->IsValid() )
340         {
341             delete m_pResourceManager, m_pResourceManager = NULL;
342             throw MissingResourceException();
343         }
344 
345         // supported resource types so far: strings
346         m_aResourceTypes[ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "string" ) ) ] =
347             ResourceTypePtr( new StringResourceAccess );
348     }
349 
350     //--------------------------------------------------------------------
~OpenOfficeResourceBundle()351     OpenOfficeResourceBundle::~OpenOfficeResourceBundle()
352     {
353         delete m_pResourceManager;
354     }
355 
356     //--------------------------------------------------------------------
getParent()357     Reference< XResourceBundle > SAL_CALL OpenOfficeResourceBundle::getParent() throw (RuntimeException)
358     {
359         ::osl::MutexGuard aGuard( m_aMutex );
360         return m_xParent;
361     }
362 
363     //--------------------------------------------------------------------
setParent(const Reference<XResourceBundle> & _parent)364     void SAL_CALL OpenOfficeResourceBundle::setParent( const Reference< XResourceBundle >& _parent ) throw (RuntimeException)
365     {
366         ::osl::MutexGuard aGuard( m_aMutex );
367         m_xParent = _parent;
368     }
369 
370     //--------------------------------------------------------------------
getLocale()371     Locale SAL_CALL OpenOfficeResourceBundle::getLocale(  ) throw (RuntimeException)
372     {
373         ::osl::MutexGuard aGuard( m_aMutex );
374         return m_aLocale;
375     }
376 
377     //--------------------------------------------------------------------
impl_getResourceTypeAndId_nothrow(const::rtl::OUString & _key,ResourceTypePtr & _out_resourceType,sal_Int32 & _out_resourceId) const378     bool OpenOfficeResourceBundle::impl_getResourceTypeAndId_nothrow( const ::rtl::OUString& _key, ResourceTypePtr& _out_resourceType, sal_Int32& _out_resourceId ) const
379     {
380         sal_Int32 typeSeparatorPos = _key.indexOf( ':' );
381         if ( typeSeparatorPos == -1 )
382             // invalid key
383             return false;
384 
385         ::rtl::OUString resourceType = _key.copy( 0, typeSeparatorPos );
386 
387         ResourceTypes::const_iterator typePos = m_aResourceTypes.find( resourceType );
388         if ( typePos == m_aResourceTypes.end() )
389             // don't know this resource type
390             return false;
391 
392         _out_resourceType = typePos->second;
393         _out_resourceId = _key.copy( typeSeparatorPos + 1 ).toInt32();
394         return true;
395     }
396 
397     //--------------------------------------------------------------------
impl_getDirectElement_nothrow(const::rtl::OUString & _key,Any & _out_Element) const398     bool OpenOfficeResourceBundle::impl_getDirectElement_nothrow( const ::rtl::OUString& _key, Any& _out_Element ) const
399     {
400         ResourceTypePtr resourceType;
401         sal_Int32 resourceId( 0 );
402         if ( !impl_getResourceTypeAndId_nothrow( _key, resourceType, resourceId ) )
403             return false;
404 
405         if ( !m_pResourceManager->IsAvailable( resourceType->getResourceType(), resourceId ) )
406             // no such resource with the given type/id
407             return false;
408 
409         _out_Element = resourceType->getResource( *m_pResourceManager, resourceId );
410         return _out_Element.hasValue();
411     }
412 
413     //--------------------------------------------------------------------
getDirectElement(const::rtl::OUString & _key)414     Any SAL_CALL OpenOfficeResourceBundle::getDirectElement( const ::rtl::OUString& _key ) throw (RuntimeException)
415     {
416         ::osl::MutexGuard aGuard( m_aMutex );
417 
418         Any aElement;
419         impl_getDirectElement_nothrow( _key, aElement );
420         return aElement;
421     }
422 
423     //--------------------------------------------------------------------
getByName(const::rtl::OUString & _key)424     Any SAL_CALL OpenOfficeResourceBundle::getByName( const ::rtl::OUString& _key ) throw (NoSuchElementException, WrappedTargetException, RuntimeException)
425     {
426         ::osl::MutexGuard aGuard( m_aMutex );
427 
428         Any aElement;
429         if ( !impl_getDirectElement_nothrow( _key, aElement ) )
430         {
431             if ( m_xParent.is() )
432                 aElement = m_xParent->getByName( _key );
433         }
434 
435         if ( !aElement.hasValue() )
436             throw NoSuchElementException( ::rtl::OUString(), *this );
437 
438         return aElement;
439     }
440 
441     //--------------------------------------------------------------------
getElementNames()442     Sequence< ::rtl::OUString > SAL_CALL OpenOfficeResourceBundle::getElementNames(  ) throw (RuntimeException)
443     {
444         ::osl::MutexGuard aGuard( m_aMutex );
445         OSL_ENSURE( false, "OpenOfficeResourceBundle::getElementNames: not implemented!" );
446             // the (Simple)ResManager does not provide an API to enumerate the resources
447         return Sequence< ::rtl::OUString >( );
448     }
449 
450     //--------------------------------------------------------------------
hasByName(const::rtl::OUString & _key)451     ::sal_Bool SAL_CALL OpenOfficeResourceBundle::hasByName( const ::rtl::OUString& _key ) throw (RuntimeException)
452     {
453         ::osl::MutexGuard aGuard( m_aMutex );
454 
455         ResourceTypePtr resourceType;
456         sal_Int32 resourceId( 0 );
457         if ( !impl_getResourceTypeAndId_nothrow( _key, resourceType, resourceId ) )
458             return sal_False;
459 
460         if ( !m_pResourceManager->IsAvailable( resourceType->getResourceType(), resourceId ) )
461             return sal_False;
462 
463         return sal_True;
464     }
465 
466     //--------------------------------------------------------------------
getElementType()467     Type SAL_CALL OpenOfficeResourceBundle::getElementType(  ) throw (RuntimeException)
468     {
469         return ::cppu::UnoType< Any >::get();
470     }
471 
472     //--------------------------------------------------------------------
hasElements()473     ::sal_Bool SAL_CALL OpenOfficeResourceBundle::hasElements(  ) throw (RuntimeException)
474     {
475         ::osl::MutexGuard aGuard( m_aMutex );
476         OSL_ENSURE( false, "OpenOfficeResourceBundle::hasElements: not implemented!" );
477             // the (Simple)ResManager does not provide an API to enumerate the resources
478         return ::sal_Bool( );
479     }
480 
481 //........................................................................
482 } // namespace res
483 //........................................................................
484 
485 #endif // EXTENSIONS_SOURCE_RESOURCE_OOORESOURCELOADER_CXX
486