1 /* -*- Mode: Java; 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 package com.sun.star.uno;
21 
22 /**
23  * This class provides static methods which aim at exploring the contents of an
24  * Any and extracting its value.
25  *
26  * <p>All public methods take an Object argument that either is the immediate object,
27  * such as Boolean, Type, interface implementation, or an Any that contains an
28  * object.</p>
29  *
30  * <p>The methods which extract the value do a widening conversion. See the
31  * method comments for the respective conversions.</p>
32  */
33 public class AnyConverter
34 {
35     /**
36      * Determines the type of an Any object.
37      *
38      * @param object any object.
39      * @return type object.
40      */
getType( Object object )41     public static Type getType( Object object )
42     {
43         Type t;
44         if (null == object)
45         {
46             t = m_XInterface_type;
47         }
48         else if (object instanceof Any)
49         {
50             t = ((Any)object).getType();
51             // nested any
52             if (TypeClass.ANY_value == t.getTypeClass().getValue())
53                 return getType( ((Any)object).getObject() );
54         }
55         else
56         {
57             t = new Type( object.getClass() );
58         }
59         return t;
60     }
61 
62     /**
63      * Checks if the any contains the idl type <code>void</code>.
64      *
65      * @param object the object to check.
66      * @return true when the any is void, false otherwise.
67      */
isVoid(Object object)68     public static boolean isVoid(Object object){
69         return containsType(TypeClass.VOID, object);
70     }
71 
72     /**
73      * Checks if the any contains a value of the idl type <code>char</code>.
74      *
75      * @param object the object to check.
76      * @return true when the any contains a char, false otherwise.
77      */
isChar(Object object)78     public static boolean isChar(Object object){
79         return containsType(TypeClass.CHAR, object);
80     }
81 
82     /**
83      * Checks if the any contains a value of the idl type <code>boolean</code>.
84      *
85      * @param object the object to check.
86      * @return true when the any contains a boolean, false otherwise.
87      */
isBoolean(Object object)88     public static boolean isBoolean(Object object){
89         return containsType(TypeClass.BOOLEAN, object);
90     }
91 
92     /**
93      * Checks if the any contains a value of the idl type <code>byte</code>.
94      *
95      * @param object the object to check.
96      * @return true when the any contains a byte, false otherwise.
97      */
isByte(Object object)98     public static boolean isByte(Object object){
99         return containsType(TypeClass.BYTE, object);
100     }
101 
102     /**
103      * Checks if the any contains a value of the idl type <code>short</code>.
104      *
105      * @param object the object to check.
106      * @return true when the any contains a short, false otherwise.
107      */
isShort(Object object)108     public static boolean isShort(Object object){
109         return containsType(TypeClass.SHORT, object);
110     }
111 
112     /**
113      * Checks if the any contains a value of the idl type <code>long</code>
114      * (which maps to a java-int).
115      *
116      * @param object the object to check.
117      * @return true when the any contains a int, false otherwise.
118      */
isInt(Object object)119     public static boolean isInt(Object object){
120         return containsType(TypeClass.LONG, object);
121     }
122 
123     /**
124      * Checks if the any contains a value of the idl type <code>hyper</code>
125      * (which maps to a java-long).
126      *
127      * @param object the object to check.
128      * @return true when the any contains a long, false otherwise.
129      */
isLong(Object object)130     public static boolean isLong(Object object){
131         return containsType(TypeClass.HYPER, object);
132     }
133 
134     /**
135      * Checks if the any contains a value of the idl type <code>float</code>.
136      *
137      * @param object the object to check.
138      * @return true when the any contains a float, false otherwise.
139      */
isFloat(Object object)140     public static boolean isFloat(Object object){
141         return containsType(TypeClass.FLOAT, object);
142     }
143 
144     /**
145      * Checks if the any contains a value of the idl type <code>double</code>.
146      *
147      * @param object the object to check.
148      * @return true when the any contains a double, false otherwise.
149      */
isDouble(Object object)150     public static boolean isDouble(Object object){
151         return containsType(TypeClass.DOUBLE, object);
152     }
153 
154     /**
155      * Checks if the any contains a value of the idl type <code>string</code>.
156      *
157      * @param object the object to check.
158      * @return true when the any contains a string, false otherwise.
159      */
isString(Object object)160     public static boolean isString(Object object){
161         return containsType(TypeClass.STRING, object);
162     }
163 
164     /**
165      * Checks if the any contains a value of the idl type <code>enum</code>.
166      *
167      * @param object the object to check.
168      * @return true if the any contains an enum, false otherwise.
169      */
isEnum(Object object)170     public static boolean isEnum(Object object)
171     {
172         return containsType(TypeClass.ENUM, object);
173     }
174 
175     /**
176      * Checks if the any contains a value of the idl type <code>type</code>.
177      *
178      * @param object the object to check.
179      * @return true when the any contains a type, false otherwise.
180      */
isType(Object object)181     public static boolean isType(Object object){
182         return containsType(TypeClass.TYPE, object);
183     }
184 
185     /**
186      * Checks if the any contains an interface, struct, exception, sequence or enum.
187      *
188      * <p>If <em>object</em> is an any with an interface type, then true is also
189      * returned if the any contains a null reference. This is because interfaces
190      * are allowed to have a null value contrary to other UNO types.</p>
191      *
192      * @param object the object to check.
193      * @return true if the any contains an object.
194      */
isObject(Object object)195     public static boolean isObject(Object object)
196     {
197         int tc = getType(object).getTypeClass().getValue();
198         return (TypeClass.INTERFACE_value == tc ||
199                 TypeClass.STRUCT_value == tc ||
200                 TypeClass.EXCEPTION_value == tc ||
201                 TypeClass.SEQUENCE_value == tc ||
202                 TypeClass.ENUM_value == tc);
203     }
204 
205     /**
206      * Checks if the any contains UNO idl sequence value (meaning a java array
207      * containing elements which are values of UNO idl types).
208      *
209      * @param object the object to check.
210      * @return true when the any contains an object which implements interfaces,
211      * false otherwise.
212      */
isArray(Object object)213     public static boolean isArray(Object object){
214         return containsType(TypeClass.SEQUENCE, object);
215     }
216 
217     /**
218      * Converts a Char object or an Any object containing a Char object into a
219      * simple char.
220      *
221      * @param object the object to convert.
222      * @return the char contained within the object.
223      * @throws com.sun.star.lang.IllegalArgumentException in case no char is
224      * contained within object.
225      *
226      * @see #isChar
227      */
toChar(Object object)228     public static char toChar(Object object) throws  com.sun.star.lang.IllegalArgumentException{
229         Character ret= (Character)convertSimple(TypeClass.CHAR, null, object);
230         return ret.charValue();
231     }
232 
233     /**
234      * Converts a Boolean object or an Any object containing a Boolean object
235      * into a simple boolean.
236      *
237      * @param object the object to convert.
238      * @return the boolean contained within the object
239      * @throws com.sun.star.lang.IllegalArgumentException in case no boolean is
240      * contained within object
241      *
242      * @see #isBoolean
243     */
toBoolean(Object object)244     public static boolean toBoolean(Object object) throws  com.sun.star.lang.IllegalArgumentException{
245         Boolean ret= (Boolean)convertSimple(TypeClass.BOOLEAN, null, object);
246         return ret.booleanValue();
247     }
248 
249     /**
250      * Converts a Byte object or an Any object containing a Byte object into a
251      * simple byte.
252      *
253      * @param object the object to convert.
254      * @return the boolean contained within the object.
255      * @throws com.sun.star.lang.IllegalArgumentException in case no byte is
256      * contained within object.
257      *
258      * @see #isBoolean
259      */
toByte(Object object)260     public static byte toByte(Object object) throws   com.sun.star.lang.IllegalArgumentException{
261         Byte ret= (Byte)convertSimple(TypeClass.BYTE, null, object);
262         return ret.byteValue();
263     }
264 
265     /**
266      * Converts a number object into a simple short and allows widening conversions.
267      *
268      * <p>Allowed argument types are Byte, Short or Any containing these types.</p>
269      *
270      * @param object the object to convert.
271      * @throws com.sun.star.lang.IllegalArgumentException in case no short or
272      * byte is contained within object.
273      *
274      * @return the short contained within the object.
275      */
toShort(Object object)276     public static short toShort(Object object) throws   com.sun.star.lang.IllegalArgumentException{
277         Short ret= (Short)convertSimple(TypeClass.SHORT, null, object);
278         return ret.shortValue();
279     }
280     /**
281      * Converts a number object into an idl unsigned short and allows widening
282      * conversions.
283      *
284      * <p>Allowed argument types are Anies containing idl unsigned short values.</p>
285      *
286      * @param object the object to convert.
287      * @throws com.sun.star.lang.IllegalArgumentException in case no idl unsigned
288      * short is contained within Any.
289      *
290      * @return an (unsigned) short.
291      */
toUnsignedShort(Object object)292     public static short toUnsignedShort(Object object)
293         throws com.sun.star.lang.IllegalArgumentException
294     {
295         Short ret= (Short)convertSimple(TypeClass.UNSIGNED_SHORT, null, object);
296         return ret.shortValue();
297     }
298 
299     /**
300      * Converts a number object into a simple int and allows widening conversions.
301      *
302      * <p>Allowed argument types are Byte, Short, Integer or Any containing these
303      * types.</p>
304      *
305      * @param object the object to convert.
306      * @throws com.sun.star.lang.IllegalArgumentException in case no short, byte
307      * or int is contained within object.
308      *
309      * @return the int contained within the object.
310      */
toInt(Object object)311     public static int toInt(Object object) throws  com.sun.star.lang.IllegalArgumentException{
312         Integer ret= (Integer) convertSimple( TypeClass.LONG, null, object);
313         return ret.intValue();
314     }
315     /**
316      * Converts a number object into an idl unsigned long and allows widening
317      * conversions.
318      *
319      * <p>Allowed argument types are Anies containing idl unsigned short or
320      * unsigned long values.</p>
321      *
322      * @param object the object to convert.
323      * @throws com.sun.star.lang.IllegalArgumentException in case no idl unsigned
324      * short nor unsigned long is contained within Any.
325      *
326      * @return an (unsigned) int.
327      */
toUnsignedInt(Object object)328     public static int toUnsignedInt(Object object)
329         throws  com.sun.star.lang.IllegalArgumentException
330     {
331         Integer ret = (Integer)convertSimple(TypeClass.UNSIGNED_LONG, null, object);
332         return ret.intValue();
333     }
334 
335     /**
336      * Converts a number object into a simple long and allows widening conversions.
337      *
338      * <p>Allowed argument types are Byte, Short, Integer, Long or Any containing
339      * these types.</p>
340      *
341      * @param object the object to convert.
342      * @throws com.sun.star.lang.IllegalArgumentException in case no short, byte,
343      * int or long is contained within object.
344      *
345      * @return the long contained within the object.
346      */
toLong(Object object)347     public static long toLong(Object object) throws   com.sun.star.lang.IllegalArgumentException{
348         Long ret= (Long) convertSimple( TypeClass.HYPER, null, object);
349         return ret.longValue();
350     }
351     /**
352      * Converts a number object into an idl unsigned hyper and allows widening
353      * conversions.
354      *
355      * <p>Allowed argument types are Anies containing idl unsigned short, unsigned
356      * long or unsigned hyper values.</p>
357      *
358      * @param object the object to convert.
359      * @throws com.sun.star.lang.IllegalArgumentException in case no idl unsigned
360      * short, nor unsigned long nor unsigned hyper is contained within object.
361      *
362      * @return an (unsigned) long.
363      */
toUnsignedLong(Object object)364     public static long toUnsignedLong(Object object)
365         throws com.sun.star.lang.IllegalArgumentException
366     {
367         Long ret = (Long)convertSimple(TypeClass.UNSIGNED_HYPER, null, object);
368         return ret.longValue();
369     }
370 
371     /**
372      * Converts a number object into a simple float and allows widening conversions.
373      *
374      * <p>Allowed argument types are Byte, Short, Float or Any containing these
375      * types.</p>
376      *
377      * @param object the object to convert.
378      * @throws com.sun.star.lang.IllegalArgumentException in case no byte, short
379      * or float is contained within object.
380      *
381      * @return the float contained within the object.
382      */
toFloat(Object object)383     public static float toFloat(Object object) throws com.sun.star.lang.IllegalArgumentException{
384         Float ret= (Float) convertSimple( TypeClass.FLOAT,null, object);
385         return ret.floatValue();
386     }
387 
388     /**
389      * Converts a number object into a simple double and allows widening conversions.
390      *
391      * <p>Allowed argument types are Byte, Short, Int, Float, Double or Any
392      * containing these types.</p>
393      *
394      * @param object the object to convert.
395      * @throws com.sun.star.lang.IllegalArgumentException in case no byte, short,
396      * int, float or double is contained within object.
397      *
398      * @return the double contained within the object.
399      */
toDouble(Object object)400     public static double toDouble(Object object) throws com.sun.star.lang.IllegalArgumentException {
401         Double ret= (Double) convertSimple( TypeClass.DOUBLE, null, object);
402         return ret.doubleValue();
403     }
404 
405     /**
406      * Converts a string or an any containing a string into a string.
407      *
408      * @param object the object to convert.
409      * @throws com.sun.star.lang.IllegalArgumentException in case no string is
410      * contained within object.
411      *
412      * @return the string contained within the object.
413      */
toString(Object object)414     public static String toString(Object object) throws com.sun.star.lang.IllegalArgumentException {
415         return (String) convertSimple( TypeClass.STRING, null, object);
416     }
417 
418     /**
419      * Converts a Type or an any containing a Type into a Type.
420      *
421      * @param object the object to convert.
422      * @throws com.sun.star.lang.IllegalArgumentException in case no type is
423      * contained within object.
424      *
425      * @return the type contained within the object.
426      */
toType(Object object)427     public static Type toType(Object object) throws com.sun.star.lang.IllegalArgumentException {
428         return (Type) convertSimple( TypeClass.TYPE, null, object);
429     }
430 
431     /**
432      * Converts a UNO object (struct, exception, sequence, enum or interface) or
433      * an Any containing these types into a UNO object of a specified destination
434      * type.
435      *
436      * <p> For interfaces, the argument <em>object</em> is queried for the interface
437      * specified by the <em>type</em> argument.</p>
438      *
439      * <p>That query (UnoRuntime.queryInterface) might return null, if the interface
440      * is not implemented or a null-ref or a VOID any is given.</p>
441      *
442      * @param type type of the returned value.
443      * @param object the object that is to be converted.
444      * @throws com.sun.star.lang.IllegalArgumentException in case conversion is
445      * not possible.
446      *
447      * @return destination object.
448      */
toObject(Type type, Object object)449     public static Object toObject(Type type, Object object)
450         throws com.sun.star.lang.IllegalArgumentException
451     {
452         return convertSimple( type.getTypeClass(), type, object );
453     }
454     /**
455      * Converts a UNO object (struct, exception, sequence, enum or interface) or
456      * an Any containing these types into a UNO object of a specified destination
457      * type.
458      *
459      * <p>For interfaces, the argument <em>object</em> is queried for the interface
460      * specified by the <em>type</em> argument. That query (UnoRuntime.queryInterface)
461      * might return null, if the interface is not implemented or a null-ref or a
462      * VOID any is given.</p>
463      *
464      * @param clazz class of the returned value.
465      * @param object the object that is to be converted.
466      * @throws com.sun.star.lang.IllegalArgumentException in case conversion is
467      * not possible.
468      *
469      * @return destination object.
470      */
toObject(Class<?> clazz, Object object)471     public static Object toObject(Class<?> clazz, Object object)
472         throws com.sun.star.lang.IllegalArgumentException
473     {
474         return toObject( new Type( clazz ), object );
475     }
476 
477     /**
478      * Converts an array or an any containing an array into an array.
479      *
480      * @param object the object to convert.
481      * @throws com.sun.star.lang.IllegalArgumentException in case no array is
482      * contained within object.
483      *
484      * @return the array contained within the object.
485      */
toArray( Object object)486     public static Object toArray( Object object) throws com.sun.star.lang.IllegalArgumentException {
487         return convertSimple( TypeClass.SEQUENCE, null, object);
488     }
489 
490     /**
491      * Examines the argument <em>object</em> if is correspond to the type in
492      * argument <em>what</em>.
493      *
494      * <p><em>object</em> is either matched directly against the type or if it is
495      * an any then the contained object is matched against the type.</p>
496      */
containsType( TypeClass what, Object object)497     private static boolean containsType( TypeClass what, Object object){
498         return (getType(object).getTypeClass().getValue() == what.getValue());
499     }
500 
501     private static final Type m_XInterface_type = new Type( XInterface.class );
502 
convertSimple( TypeClass destTClass, Type destType, Object object_ )503     private static Object convertSimple( TypeClass destTClass, Type destType, Object object_ )
504         throws com.sun.star.lang.IllegalArgumentException
505     {
506         Object object;
507         Type type;
508         if (object_ instanceof Any) {
509             // unbox
510             Any a = (Any)object_;
511             object = a.getObject();
512             type = a.getType();
513             // nested any
514             if (TypeClass.ANY_value == type.getTypeClass().getValue())
515                 return convertSimple( destTClass, destType, object );
516         } else {
517             object = object_;
518             type = (null == object ? m_XInterface_type : new Type( object.getClass() ));
519         }
520 
521         int tc = type.getTypeClass().getValue();
522         int dest_tc = destTClass.getValue();
523 
524         if (null == object) {
525             // special for interfaces
526             if (TypeClass.INTERFACE_value == tc && dest_tc == tc)
527                 return null;
528         } else {
529             switch (dest_tc) {
530             case TypeClass.CHAR_value:
531                 if (tc == TypeClass.CHAR_value)
532                     return object;
533                 break;
534             case TypeClass.BOOLEAN_value:
535                 if (tc == TypeClass.BOOLEAN_value)
536                     return object;
537                 break;
538             case TypeClass.BYTE_value:
539                 if (tc == TypeClass.BYTE_value)
540                     return object;
541                 break;
542             case TypeClass.SHORT_value:
543                 switch (tc) {
544                 case TypeClass.BYTE_value:
545                     return Short.valueOf( ((Byte)object).byteValue() );
546                 case TypeClass.SHORT_value:
547                     return object;
548                 }
549                 break;
550             case TypeClass.UNSIGNED_SHORT_value:
551                 switch (tc) {
552                 case TypeClass.UNSIGNED_SHORT_value:
553                     return object;
554                 }
555                 break;
556             case TypeClass.LONG_value:
557                 switch (tc) {
558                 case TypeClass.BYTE_value:
559                     return Integer.valueOf( ((Byte)object).byteValue() );
560                 case TypeClass.SHORT_value:
561                 case TypeClass.UNSIGNED_SHORT_value:
562                     return Integer.valueOf( ((Short)object).shortValue() );
563                 case TypeClass.LONG_value:
564                     return object;
565                 }
566                 break;
567             case TypeClass.UNSIGNED_LONG_value:
568                 switch (tc) {
569                 case TypeClass.UNSIGNED_SHORT_value:
570                     return Integer.valueOf( ((Short)object).shortValue() );
571                 case TypeClass.UNSIGNED_LONG_value:
572                     return object;
573                 }
574                 break;
575             case TypeClass.HYPER_value:
576                 switch (tc) {
577                 case TypeClass.BYTE_value:
578                     return Long.valueOf( ((Byte)object).byteValue() );
579                 case TypeClass.SHORT_value:
580                 case TypeClass.UNSIGNED_SHORT_value:
581                     return Long.valueOf( ((Short)object).shortValue() );
582                 case TypeClass.LONG_value:
583                 case TypeClass.UNSIGNED_LONG_value:
584                     return Long.valueOf( ((Integer)object).intValue() );
585                 case TypeClass.HYPER_value:
586                     return object;
587                 }
588                 break;
589             case TypeClass.UNSIGNED_HYPER_value:
590                 switch (tc) {
591                 case TypeClass.UNSIGNED_SHORT_value:
592                     return Long.valueOf( ((Short)object).shortValue() );
593                 case TypeClass.UNSIGNED_LONG_value:
594                     return Long.valueOf( ((Integer)object).intValue() );
595                 case TypeClass.UNSIGNED_HYPER_value:
596                     return object;
597                 }
598                 break;
599             case TypeClass.FLOAT_value:
600                 switch (tc) {
601                 case TypeClass.BYTE_value:
602                     return new Float( ((Byte)object).byteValue() );
603                 case TypeClass.SHORT_value:
604                     return new Float( ((Short)object).shortValue() );
605                 case TypeClass.FLOAT_value:
606                     return object;
607                 }
608                 break;
609             case TypeClass.DOUBLE_value:
610                 switch (tc) {
611                 case TypeClass.BYTE_value:
612                     return new Double( ((Byte)object).byteValue() );
613                 case TypeClass.SHORT_value:
614                     return new Double( ((Short)object).shortValue() );
615                 case TypeClass.LONG_value:
616                     return new Double( ((Integer)object).intValue() );
617                 case TypeClass.FLOAT_value:
618                     return new Double( ((Float)object).floatValue() );
619                 case TypeClass.DOUBLE_value:
620                     return object;
621                 }
622                 break;
623             case TypeClass.ENUM_value:
624                 if (tc == TypeClass.ENUM_value &&
625                     (null == destType || destType.equals( type ) /* optional destType */))
626                 {
627                     return object;
628                 }
629                 break;
630             case TypeClass.STRING_value:
631                 if (tc == TypeClass.STRING_value)
632                     return object;
633                 break;
634             case TypeClass.TYPE_value:
635                 if (tc == TypeClass.TYPE_value)
636                     return object;
637                 break;
638             case TypeClass.INTERFACE_value:
639                 // Because object is a class, not an interface, it is
640                 // controversial what kind of Type "new Type(object.class)"
641                 // above should return (UNKNOWN or INTERFACE), so that we should
642                 // not check here for "tc == TypeClass.INTERFACE_value".
643                 // Instead, we check whether object (indirectly) derives from
644                 // XInterface:
645                 if (object instanceof XInterface)
646                     return UnoRuntime.queryInterface( destType, object );
647                 break;
648             case TypeClass.STRUCT_value:
649             case TypeClass.EXCEPTION_value:
650                 if (destType.isSupertypeOf(type)) {
651                     return object;
652                 }
653                 break;
654             case TypeClass.SEQUENCE_value:
655                 if (tc == TypeClass.SEQUENCE_value &&
656                     (null == destType || destType.equals( type ) /* optional destType */))
657                 {
658                     return object;
659                 }
660                 break;
661             }
662         }
663         throw new com.sun.star.lang.IllegalArgumentException(
664             "The Argument did not hold the proper type");
665     }
666 }
667 
668 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
669