1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_extensions.hxx"
30 #include "res_services.hxx"
31 
32 #include <vos/mutex.hxx>
33 #include <uno/lbnames.h>			// CPPU_CURRENT_LANGUAGE_BINDING_NAME macro, which specify the environment type
34 #include <cppuhelper/factory.hxx>	// helper for factories
35 #include <cppuhelper/implbase3.hxx>	// helper for implementations
36 
37 #include <com/sun/star/lang/XServiceInfo.hpp>
38 #include <com/sun/star/script/XInvocation.hpp>
39 #include <com/sun/star/script/XTypeConverter.hpp>
40 #include <com/sun/star/reflection/InvocationTargetException.hpp>
41 #include <com/sun/star/beans/XExactName.hpp>
42 #include <com/sun/star/beans/PropertyValue.hpp>
43 #include <com/sun/star/beans/PropertyState.hpp>
44 
45 #include <tools/resmgr.hxx>
46 #include <tools/rcid.h>
47 #include <tools/resary.hxx>
48 #include <vcl/svapp.hxx>
49 
50 #include <rtl/ustring.hxx>
51 #include <rtl/strbuf.hxx>
52 
53 using namespace vos;
54 using namespace rtl;
55 using namespace com::sun::star::uno;
56 using namespace com::sun::star::lang;
57 using namespace com::sun::star::registry;
58 using namespace com::sun::star::script;
59 using namespace com::sun::star::beans;
60 using namespace com::sun::star::reflection;
61 
62 //------------------------------------------------------------------------
63 //------------------------------------------------------------------------
64 //------------------------------------------------------------------------
65 class ResourceService : public cppu::WeakImplHelper3< XInvocation, XExactName, XServiceInfo >
66 {
67 public:
68 								ResourceService( const Reference< XMultiServiceFactory > & );
69 								~ResourceService();
70 
71 	// XServiceInfo
72 	OUString SAL_CALL			getImplementationName() throw();
73     sal_Bool 	 SAL_CALL			supportsService(const OUString& ServiceName) throw();
74     Sequence< OUString > SAL_CALL	getSupportedServiceNames(void) throw();
75 
76     static Sequence< OUString > getSupportedServiceNames_Static(void) throw();
77 	static OUString 			getImplementationName_Static() throw()
78 								{
79 									return OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.extensions.ResourceService"));
80 								}
81     static Reference< XInterface > Create( const Reference< XComponentContext >& _rxContext );
82 
83 	// XExactName
84 	OUString  SAL_CALL			getExactName( const OUString & ApproximateName ) throw(RuntimeException);
85 
86 	// XInvokation
87     Reference< XIntrospectionAccess >  SAL_CALL getIntrospection(void)  throw(RuntimeException);
88     Any  SAL_CALL				invoke(const OUString& FunctionName, const Sequence< Any >& Params, Sequence< sal_Int16 >& OutParamIndex, Sequence< Any >& OutParam) throw(IllegalArgumentException, CannotConvertException, InvocationTargetException, RuntimeException);
89     void  SAL_CALL				setValue(const OUString& PropertyName, const Any& Value) throw(UnknownPropertyException, CannotConvertException, InvocationTargetException, RuntimeException);
90     Any  SAL_CALL				getValue(const OUString& PropertyName) throw(UnknownPropertyException, RuntimeException);
91     sal_Bool  SAL_CALL				hasMethod(const OUString& Name)  throw(RuntimeException);
92     sal_Bool  SAL_CALL				hasProperty(const OUString& Name)  throw(RuntimeException);
93 private:
94 	Reference< XTypeConverter >			getTypeConverter() const;
95 	Reference< XInvocation >			getDefaultInvocation() const;
96 
97 	Reference< XMultiServiceFactory >	xSMgr;
98 	Reference< XInvocation >			xDefaultInvocation;
99 	Reference< XTypeConverter >			xTypeConverter;
100 	OUString								aFileName;
101 	ResMgr *							pResMgr;
102 };
103 
104 
105 //-----------------------------------------------------------------------------
106 ResourceService::ResourceService( const Reference< XMultiServiceFactory > & rSMgr )
107 	: xSMgr( rSMgr )
108 	, pResMgr( NULL )
109 {
110 }
111 
112 //-----------------------------------------------------------------------------
113 Reference< XInterface > ResourceService::Create( const Reference< XComponentContext >& _rxContext )
114 {
115     Reference< XMultiServiceFactory > xFactory( _rxContext->getServiceManager(), UNO_QUERY_THROW );
116     return *( new ResourceService( xFactory ) );
117 }
118 
119 //-----------------------------------------------------------------------------
120 ResourceService::~ResourceService()
121 {
122 	delete pResMgr;
123 }
124 
125 // XServiceInfo
126 OUString ResourceService::getImplementationName() throw()
127 {
128 	return getImplementationName_Static();
129 }
130 
131 // XServiceInfo
132 sal_Bool SAL_CALL ResourceService::supportsService(const OUString& ServiceName) throw()
133 {
134 	Sequence< OUString > aSNL = getSupportedServiceNames();
135 	const OUString * pArray = aSNL.getConstArray();
136 	for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
137 		if( pArray[i] == ServiceName )
138 			return sal_True;
139 	return sal_False;
140 }
141 
142 // XServiceInfo
143 Sequence< OUString > SAL_CALL ResourceService::getSupportedServiceNames(void) throw()
144 {
145 	return getSupportedServiceNames_Static();
146 }
147 
148 // ResourceService
149 Sequence< OUString > ResourceService::getSupportedServiceNames_Static(void) throw()
150 {
151 	Sequence< OUString > aSNS( 1 );
152 	aSNS.getArray()[0] = OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.resource.VclStringResourceLoader"));
153 	return aSNS;
154 }
155 
156 // ResourceService
157 Reference< XTypeConverter > ResourceService::getTypeConverter() const
158 {
159 	OGuard aGuard( Application::GetSolarMutex() );
160 	if( xSMgr.is() )
161 	{
162 		Reference< XTypeConverter > xConv( xSMgr->createInstance( OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.script.Converter" ))), UNO_QUERY );
163 		((ResourceService*)this)->xTypeConverter = xConv;
164 	}
165 	return xTypeConverter;
166 }
167 
168 // ResourceService
169 Reference< XInvocation > ResourceService::getDefaultInvocation() const
170 {
171 	OGuard aGuard( Application::GetSolarMutex() );
172 	/* f�hrt zur Zeit noch zu einer rekursion
173 	if( xSMgr.is() )
174 	{
175 		Reference< XSingleServiceFactory > xFact( xSMgr->createInstance( OUString::createFromAscii("com.sun.star.script.Invocation") ), UNO_QUERY );
176 		if( xFact.is() )
177 		{
178 			Sequence< Any > aArgs( 1 );
179 			Reference< XInterface > xThis( *this );
180 			aArgs.getArray()[0].set( &xThis, XInterface_Reference< get >lection() );
181 			Reference< XInvokation > xI( xFact->createInstanceWithArguments( aArgs ), UNO_QUERY );
182 			((ResourceService*)this)->xDefaultInvocation = xI;
183 		}
184 	}
185 	*/
186 	return xDefaultInvocation;
187 }
188 
189 // XExactName
190 OUString	SAL_CALL ResourceService::getExactName( const OUString & ApproximateName ) throw(RuntimeException)
191 {
192 	OUString aName( ApproximateName );
193 	aName = aName.toAsciiLowerCase();
194 	if( aName.equalsAscii("filename") )
195 		return OUString(RTL_CONSTASCII_USTRINGPARAM("FileName"));
196 	else if( aName.equalsAscii("getstring" ))
197 		return OUString(RTL_CONSTASCII_USTRINGPARAM("getString"));
198 	else if( aName.equalsAscii("getstrings" ))
199 		return OUString(RTL_CONSTASCII_USTRINGPARAM("getStrings"));
200 	else if( aName.equalsAscii("hasstring") )
201 		return OUString(RTL_CONSTASCII_USTRINGPARAM("hasString"));
202 	else if( aName.equalsAscii("hasstrings") )
203 		return OUString(RTL_CONSTASCII_USTRINGPARAM("hasStrings"));
204 	else if( aName.equalsAscii("getstringlist") )
205 		return OUString(RTL_CONSTASCII_USTRINGPARAM("getStringList"));
206 	else if( aName.equalsAscii("hasStringList") )
207 		return OUString(RTL_CONSTASCII_USTRINGPARAM("hasStringList"));
208 	Reference< XExactName > xEN( getDefaultInvocation(), UNO_QUERY );
209 	if( xEN.is() )
210 		return xEN->getExactName( ApproximateName );
211 	return OUString();
212 }
213 
214 // XInvokation
215 Reference< XIntrospectionAccess > SAL_CALL ResourceService::getIntrospection(void)
216 	throw(RuntimeException)
217 {
218 	Reference< XInvocation > xI = getDefaultInvocation();
219 	if( xI.is() )
220 		return xI->getIntrospection();
221 	return Reference< XIntrospectionAccess >();
222 }
223 
224 // XInvokation
225 Any SAL_CALL ResourceService::invoke
226 (
227 	const OUString& FunctionName,
228 	const Sequence< Any >& Params,
229 	Sequence< sal_Int16 >& OutParamIndex,
230 	Sequence< Any >& OutParam
231 )
232 	throw(IllegalArgumentException, CannotConvertException, InvocationTargetException, RuntimeException)
233 {
234     Any aRet;
235 	if( FunctionName.equalsAscii("getString")
236         || FunctionName.equalsAscii("getStrings" )
237         || FunctionName.equalsAscii("hasString" )
238         || FunctionName.equalsAscii("hasStrings" )
239         )
240 	{
241         sal_Int32 nElements = Params.getLength();
242         if( nElements < 1 )
243             throw IllegalArgumentException();
244         if( nElements > 1 && (FunctionName.equalsAscii("getString") || FunctionName.equalsAscii("hasString") ) )
245             throw IllegalArgumentException();
246         if( !pResMgr )
247             throw IllegalArgumentException();
248 
249         Sequence< OUString > aStrings( Params.getLength() );
250         Sequence< sal_Bool > aBools( Params.getLength() );
251         const Any* pIn = Params.getConstArray();
252         OUString* pOutString = aStrings.getArray();
253         sal_Bool* pOutBool = aBools.getArray();
254 
255         Reference< XTypeConverter > xC = getTypeConverter();
256         bool bGetBranch = FunctionName.equalsAscii( "getString" ) || FunctionName.equalsAscii( "getStrings" );
257 
258         OGuard aGuard( Application::GetSolarMutex() );
259         for( sal_Int32 n = 0; n < nElements; n++ )
260         {
261             sal_Int32 nId = 0;
262             if( !(pIn[n] >>= nId) )
263             {
264                 if( xC.is() )
265                 {
266                     xC->convertToSimpleType( pIn[n], TypeClass_LONG ) >>= nId;
267                 }
268                 else
269                     throw CannotConvertException();
270             }
271             if( nId > 0xFFFF || nId < 0 )
272                 throw IllegalArgumentException();
273 
274             if( bGetBranch )
275             {
276                 ResId aId( (sal_uInt16)nId, *pResMgr );
277                 aId.SetRT( RSC_STRING );
278                 if( pResMgr->IsAvailable( aId ) )
279                 {
280                     String aStr( aId );
281                     pOutString[n] = aStr;
282                 }
283                 else
284                     throw IllegalArgumentException();
285             }
286             else // hasString(s)
287             {
288                 sal_Bool bRet = sal_False;
289                 if( pResMgr )
290                 {
291                     ResId aId( (sal_uInt16)nId, *pResMgr );
292                     aId.SetRT( RSC_STRING );
293                     bRet = pResMgr->IsAvailable( aId );
294                 }
295                 pOutBool[n] = bRet;
296             }
297         }
298         if( FunctionName.equalsAscii("getString") )
299             aRet <<= pOutString[0];
300         else if( FunctionName.equalsAscii("getStrings" ) )
301             aRet <<= aStrings;
302         else if( FunctionName.equalsAscii("hasString" ) )
303             aRet <<= pOutBool[0];
304         else
305             aRet <<= aBools;
306     }
307     else if( FunctionName.equalsAscii("getStringList") || FunctionName.equalsAscii("hasStringList" ) )
308     {
309         if( Params.getLength() != 1 )
310             throw IllegalArgumentException();
311         Reference< XTypeConverter > xC = getTypeConverter();
312         OGuard aGuard( Application::GetSolarMutex() );
313 
314         sal_Int32 nId = 0;
315         if( !(Params.getConstArray()[0] >>= nId) )
316         {
317             if( xC.is() )
318             {
319                 xC->convertToSimpleType( Params.getConstArray()[0], TypeClass_LONG ) >>= nId;
320             }
321             else
322                 throw CannotConvertException();
323         }
324 
325         if( FunctionName.equalsAscii("getStringList") )
326         {
327             ResId aId( (sal_uInt16)nId, *pResMgr );
328             aId.SetRT( RSC_STRINGARRAY );
329             if( pResMgr->IsAvailable( aId ) )
330             {
331                 ResStringArray aStr( aId );
332                 int nEntries = aStr.Count();
333                 Sequence< PropertyValue > aPropSeq( nEntries );
334                 PropertyValue* pOut = aPropSeq.getArray();
335                 for( int i = 0; i < nEntries; i++ )
336                 {
337                     pOut[i].Name        = aStr.GetString( i );
338                     pOut[i].Handle      = -1;
339                     pOut[i].Value     <<= aStr.GetValue( i );
340                     pOut[i].State       = PropertyState_DIRECT_VALUE;
341                 }
342                 aRet <<= aPropSeq;
343             }
344             else
345                 throw IllegalArgumentException();
346         }
347         else // hasStringList
348         {
349             sal_Bool bRet = sal_False;
350             if( pResMgr )
351             {
352                 ResId aId( (sal_uInt16)nId, *pResMgr );
353                 aId.SetRT( RSC_STRINGARRAY );
354                 bRet = pResMgr->IsAvailable( aId );
355             }
356             aRet <<= bRet;
357         }
358     }
359 	else
360 	{
361 		Reference< XInvocation > xI = getDefaultInvocation();
362 		if( xI.is() )
363 			return xI->invoke( FunctionName, Params, OutParamIndex, OutParam );
364 		else
365 			throw IllegalArgumentException();
366 	}
367 	return aRet;
368 }
369 
370 // XInvokation
371 void SAL_CALL ResourceService::setValue(const OUString& PropertyName, const Any& Value)
372 	throw(UnknownPropertyException, CannotConvertException, InvocationTargetException, RuntimeException)
373 {
374 	if( PropertyName.equalsAscii("FileName") )
375 	{
376 		OUString aName;
377 		if( !(Value >>= aName) )
378 		{
379 			Reference< XTypeConverter > xC = getTypeConverter();
380 			if( xC.is() )
381 				xC->convertToSimpleType( Value, TypeClass_STRING ) >>= aName;
382 			else
383 				throw CannotConvertException();
384 		}
385 
386 		OGuard aGuard( Application::GetSolarMutex() );
387         OStringBuffer aBuf( aName.getLength()+8 );
388         aBuf.append( OUStringToOString( aName, osl_getThreadTextEncoding() ) );
389 		ResMgr * pRM = ResMgr::CreateResMgr( aBuf.getStr() );
390 		if( !pRM )
391 			throw InvocationTargetException();
392 		if( pResMgr )
393 			delete pResMgr;
394 		pResMgr = pRM;
395 		aFileName = OStringToOUString( aBuf.makeStringAndClear(), osl_getThreadTextEncoding() );
396 	}
397 	else
398 	{
399 		Reference< XInvocation > xI = getDefaultInvocation();
400 		if( xI.is() )
401 			xI->setValue( PropertyName, Value );
402 		else
403 			throw UnknownPropertyException();
404 	}
405 }
406 
407 // XInvokation
408 Any SAL_CALL ResourceService::getValue(const OUString& PropertyName)
409 	throw(UnknownPropertyException, RuntimeException)
410 {
411 	OGuard aGuard( Application::GetSolarMutex() );
412 	if( PropertyName.equalsAscii("FileName" ))
413 		return makeAny( aFileName );
414 
415 	Reference< XInvocation > xI = getDefaultInvocation();
416 	if( xI.is() )
417 		return xI->getValue( PropertyName );
418 
419 	throw UnknownPropertyException();
420 }
421 
422 // XInvokation
423 sal_Bool SAL_CALL ResourceService::hasMethod(const OUString& Name)
424 	throw(RuntimeException)
425 {
426 	if( Name.equalsAscii("getString")     ||
427         Name.equalsAscii("getStrings")    ||
428         Name.equalsAscii("hasString")     ||
429         Name.equalsAscii("hasStrings")    ||
430         Name.equalsAscii("getStringList") ||
431         Name.equalsAscii("hasStringList")
432         )
433 		return sal_True;
434 	else
435 	{
436 		Reference< XInvocation > xI = getDefaultInvocation();
437 		if( xI.is() )
438 			return xI->hasMethod( Name );
439 		else
440 			return sal_False;
441 	}
442 }
443 
444 // XInvokation
445 sal_Bool SAL_CALL ResourceService::hasProperty(const OUString& Name)
446 	throw(RuntimeException)
447 {
448 	if( Name.equalsAscii("FileName") )
449 		return sal_True;
450 	else
451 	{
452 		Reference< XInvocation > xI = getDefaultInvocation();
453 		if( xI.is() )
454 			return xI->hasProperty( Name );
455 		else
456 			return sal_False;
457 	}
458 }
459 
460 namespace res
461 {
462     ComponentInfo getComponentInfo_VclStringResourceLoader()
463     {
464         ComponentInfo aInfo;
465         aInfo.aSupportedServices = ResourceService::getSupportedServiceNames_Static();
466         aInfo.sImplementationName = ResourceService::getImplementationName_Static();
467         aInfo.pFactory = &ResourceService::Create;
468         return aInfo;
469     }
470 }
471 
472