From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- ridljar/com/sun/star/uno/Type.java | 699 +++++++++++++++++++++++++++++++++++++ 1 file changed, 699 insertions(+) create mode 100644 ridljar/com/sun/star/uno/Type.java (limited to 'ridljar/com/sun/star/uno/Type.java') diff --git a/ridljar/com/sun/star/uno/Type.java b/ridljar/com/sun/star/uno/Type.java new file mode 100644 index 000000000..0589b64cb --- /dev/null +++ b/ridljar/com/sun/star/uno/Type.java @@ -0,0 +1,699 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +package com.sun.star.uno; + +import java.util.HashMap; + +import com.sun.star.lib.uno.typedesc.TypeDescription; + +/** + * Represents the UNO built-in type TYPE. + * + *

The UNO type is not directly mapped to java.lang.Class for at + * least two reasons. For one, some UNO types (like UNSIGNED + * SHORT) do not have a matching Java class. For another, it can be + * necessary to describe a type which is unknown to the Java runtime system + * (for example, for delaying the need of a class, so that it is possible to + * generate it on the fly.)

+ * + *

A Type is uniquely determined by its type class (a + * TypeClass) and its type name (a String); these two + * will never be null. A Type may have an additional + * "z class" (a java.lang.Class), giving a Java class type that + * corresponds to the UNO type. Also, a Type can cache a type + * description (a com.sun.star.uno.typedesc.TypeDescription), which can be + * computed and set by TypeDescription.getTypeDescription. + */ +public class Type { + // The following private static members and static initializer must come + // first in the class definition, so that the class can be initialized + // successfully: + + private static final String TYPE_NAME_VOID = "void"; + private static final String TYPE_NAME_BOOLEAN = "boolean"; + private static final String TYPE_NAME_BYTE = "byte"; + private static final String TYPE_NAME_SHORT = "short"; + private static final String TYPE_NAME_UNSIGNED_SHORT = "unsigned short"; + private static final String TYPE_NAME_LONG = "long"; + private static final String TYPE_NAME_UNSIGNED_LONG = "unsigned long"; + private static final String TYPE_NAME_HYPER = "hyper"; + private static final String TYPE_NAME_UNSIGNED_HYPER = "unsigned hyper"; + private static final String TYPE_NAME_FLOAT = "float"; + private static final String TYPE_NAME_DOUBLE = "double"; + private static final String TYPE_NAME_CHAR = "char"; + private static final String TYPE_NAME_STRING = "string"; + private static final String TYPE_NAME_TYPE = "type"; + private static final String TYPE_NAME_ANY = "any"; + + // must be sorted same as TypeClass: + private static final String[] __typeClassToTypeName = new String[] { + TYPE_NAME_VOID, + TYPE_NAME_CHAR, + TYPE_NAME_BOOLEAN, + TYPE_NAME_BYTE, + TYPE_NAME_SHORT, + TYPE_NAME_UNSIGNED_SHORT, + TYPE_NAME_LONG, + TYPE_NAME_UNSIGNED_LONG, + TYPE_NAME_HYPER, + TYPE_NAME_UNSIGNED_HYPER, + TYPE_NAME_FLOAT, + TYPE_NAME_DOUBLE, + TYPE_NAME_STRING, + TYPE_NAME_TYPE, + TYPE_NAME_ANY + }; + + private static final class TypeInfo { + TypeInfo( + TypeClass thePrimary, TypeClass theAlternative, + boolean theSequenceComponentType) + { + primary = thePrimary; + alternative = theAlternative; + sequenceComponentType = theSequenceComponentType; + } + + final TypeClass primary; + final TypeClass alternative; + final boolean sequenceComponentType; + } + + private static final HashMap, TypeInfo> __javaClassToTypeClass = + new HashMap, TypeInfo>(); + static { + __javaClassToTypeClass.put( + void.class, new TypeInfo(TypeClass.VOID, TypeClass.VOID, false)); + __javaClassToTypeClass.put( + Void.class, new TypeInfo(TypeClass.VOID, TypeClass.VOID, false)); + __javaClassToTypeClass.put( + boolean.class, + new TypeInfo(TypeClass.BOOLEAN, TypeClass.BOOLEAN, true)); + __javaClassToTypeClass.put( + Boolean.class, + new TypeInfo(TypeClass.BOOLEAN, TypeClass.BOOLEAN, false)); + __javaClassToTypeClass.put( + byte.class, new TypeInfo(TypeClass.BYTE, TypeClass.BYTE, true)); + __javaClassToTypeClass.put( + Byte.class, new TypeInfo(TypeClass.BYTE, TypeClass.BYTE, false)); + __javaClassToTypeClass.put( + short.class, + new TypeInfo(TypeClass.SHORT, TypeClass.UNSIGNED_SHORT, true)); + __javaClassToTypeClass.put( + Short.class, + new TypeInfo(TypeClass.SHORT, TypeClass.UNSIGNED_SHORT, false)); + __javaClassToTypeClass.put( + int.class, + new TypeInfo(TypeClass.LONG, TypeClass.UNSIGNED_LONG, true)); + __javaClassToTypeClass.put( + Integer.class, + new TypeInfo(TypeClass.LONG, TypeClass.UNSIGNED_LONG, false)); + __javaClassToTypeClass.put( + long.class, + new TypeInfo(TypeClass.HYPER, TypeClass.UNSIGNED_HYPER, true)); + __javaClassToTypeClass.put( + Long.class, + new TypeInfo(TypeClass.HYPER, TypeClass.UNSIGNED_HYPER, false)); + __javaClassToTypeClass.put( + float.class, new TypeInfo(TypeClass.FLOAT, TypeClass.FLOAT, true)); + __javaClassToTypeClass.put( + Float.class, new TypeInfo(TypeClass.FLOAT, TypeClass.FLOAT, false)); + __javaClassToTypeClass.put( + double.class, + new TypeInfo(TypeClass.DOUBLE, TypeClass.DOUBLE, true)); + __javaClassToTypeClass.put( + Double.class, + new TypeInfo(TypeClass.DOUBLE, TypeClass.DOUBLE, false)); + __javaClassToTypeClass.put( + char.class, new TypeInfo(TypeClass.CHAR, TypeClass.CHAR, true)); + __javaClassToTypeClass.put( + Character.class, + new TypeInfo(TypeClass.CHAR, TypeClass.CHAR, false)); + __javaClassToTypeClass.put( + String.class, + new TypeInfo(TypeClass.STRING, TypeClass.STRING, true)); + __javaClassToTypeClass.put( + Type.class, new TypeInfo(TypeClass.TYPE, TypeClass.TYPE, true)); + __javaClassToTypeClass.put( + Any.class, new TypeInfo(TypeClass.ANY, TypeClass.ANY, true)); + __javaClassToTypeClass.put( + Object.class, + new TypeInfo(TypeClass.ANY, TypeClass.INTERFACE, true)); + } + + public static final Type VOID = new Type(void.class); + public static final Type CHAR = new Type(char.class); + public static final Type BOOLEAN = new Type(boolean.class); + public static final Type BYTE = new Type(byte.class); + public static final Type SHORT = new Type(short.class); + public static final Type UNSIGNED_SHORT = new Type( + TYPE_NAME_UNSIGNED_SHORT, TypeClass.UNSIGNED_SHORT); + public static final Type LONG = new Type(int.class); + public static final Type UNSIGNED_LONG = new Type( + TYPE_NAME_UNSIGNED_LONG, TypeClass.UNSIGNED_LONG); + public static final Type HYPER = new Type(long.class); + public static final Type UNSIGNED_HYPER = new Type( + TYPE_NAME_UNSIGNED_HYPER, TypeClass.UNSIGNED_HYPER); + public static final Type FLOAT = new Type(float.class); + public static final Type DOUBLE = new Type(double.class); + public static final Type STRING = new Type(String.class); + public static final Type TYPE = new Type(Type.class); + public static final Type ANY = new Type(Any.class); + + /** + * Constructs a new Type which defaults to VOID. + */ + public Type() { + init(null, void.class, false, false, false); + } + + /** + * Constructs a new Type with the given type class and type + * name. + * + * @param typeName the type name. Must not be null. + * @param typeClass the type class. Must not be null, and must + * match the typeName (for example, it is illegal to + * combine a typeName of "void" with a + * typeClass of BOOLEAN). + */ + public Type(String typeName, TypeClass typeClass) { + _typeClass = typeClass; + _typeName = typeName; + } + + /** + * Constructs a new Type from the given + * java.lang.Class. + * + *

This is equivalent to Type(zClass, false).

+ * + * @param zClass the Java class of this type. Must not be + * null. + */ + public Type(Class zClass) { + init(null, zClass, false, false, false); + } + + /** + * Constructs a new Type from the given + * java.lang.Class, handling ambiguous cases. + * + *

In certain cases, one Java class corresponds to two UNO types (e.g., + * the Java class short[].class corresponds to both a sequence + * of SHORT and a sequence of UNSIGNED SHORT in + * UNO). In such ambiguous cases, the parameter alternative + * controls which UNO type is chosen: + *

+ *

In all other cases, the value of alternative is + * ignored.

+ * + *

This constructor cannot be used to create Type instances + * that represent (sequences of) instantiated polymorphic struct types.

+ * + * @param zClass the Java class of this type; must not be null + * @param alternative controls which UNO type to choose in case of + * ambiguities + * + * @since UDK 3.2.0 + */ + public Type(Class zClass, boolean alternative) { + init(null, zClass, alternative, false, false); + } + + private Type( + Class zClass, boolean alternative, boolean sequenceComponentType) + { + init(null, zClass, alternative, false, sequenceComponentType); + } + + /** + * Constructs a new Type from the given type description. + * + * For internal URE use only. Not to be used by client code. + * + * @param typeDescription a type description. Must not be + * null. + */ + public Type(TypeDescription typeDescription) { + _typeName = typeDescription.getTypeName(); + _typeClass = typeDescription.getTypeClass(); + _iTypeDescription = typeDescription; + } + + /** + * Constructs a new Type with the given type name. + * + * @param typeName the name of this type; must not be null. + */ + public Type(String typeName) { + if (typeName.startsWith("[]")) { + _typeName = typeName; + _typeClass = TypeClass.SEQUENCE; + return; + } + for (int i = 0; i < __typeClassToTypeName.length; ++i) { + if (__typeClassToTypeName[i].equals(typeName)) { + _typeName = typeName; + _typeClass = TypeClass.fromInt(i); + return; + } + } + int i = typeName.indexOf('<'); + try { + init( + typeName, + Class.forName(i < 0 ? typeName : typeName.substring(0, i)), + false, i >= 0, false); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + /** + * Constructs a new Type with the given type class. + * + * @param typeClass the type class of this type; must not be + * null. Only type classes for simple types are allowed + * here. + * + * @throws IllegalArgumentException if the given typeClass is + * not simple (for example, a struct or an interface type). This + * constructor could not find out the type name in such a case. + */ + public Type(TypeClass typeClass) { + if(__isTypeClassPrimitive(typeClass)) { + _typeClass = typeClass; + _typeName = __typeClassToTypeName[typeClass.getValue()]; + } + else + throw new IllegalArgumentException(typeClass + " is not primitive"); + } + + /** + * Gets the type class. + * + * @return the type class. Will never be null, but might be + * UNKNOWN. + */ + public TypeClass getTypeClass() { + return _typeClass; + } + + /** + * Gets the type name. + * + * @return the type name; will never be null + */ + public String getTypeName() { + return _typeName; + } + + /** + * Gets the Java class. + * + * @return the type name; may be null in extreme situations + * (inconsistent TypeClass, error loading a class) + */ + public Class getZClass() { + synchronized (this) { + if (_class == null) { + _class = determineClass(); + } + } + return _class; + } + + /** + * Gives the type description of this type. + * + * For internal URE use only. Not to be used by client code. + * + * @return the type description; may be null + */ + public TypeDescription getTypeDescription() { + return _iTypeDescription; + } + + /** + * Sets the type description for this type. + * + * For internal URE use only. Not to be used by client code. + * + * @param typeDescription the type description + */ + public void setTypeDescription(TypeDescription typeDescription) { + _iTypeDescription = typeDescription; + } + + /** + * Determines whether this UNO type is a supertype of another UNO type. + * + * UNO only defines the following supertype relations: + * (1) A struct type t1 is a supertype of a struct type t2, if either t1 + * and t2 are the same, or t1 is a direct or indirect parent of t2. + * (2) An exception type t1 is a supertype of an exception type t2, if + * either t1 and t2 are the same, or t1 is a direct or indirect parent + * of t2. + * (3) An interface type t1 is a supertype of an interface type t2, if + * either t1 and t2 are the same, or t1 is a direct or indirect parent + * of t2. + * + * Following the conventions of the Java UNO language binding, + * com.sun.star.uno.Exception is not considered a supertype of + * com.sun.star.uno.RuntimeException or any exception type derived from + * com.sun.star.uno.RuntimeException. + * + * @param type some Type + * @return true if this type is a supertype of the given type + * + * @since UDK 3.2.0 + */ + public boolean isSupertypeOf(Type type) { + if (_typeClass != type._typeClass) { + return false; + } + switch (_typeClass.getValue()) { + case TypeClass.SEQUENCE_value: + case TypeClass.ENUM_value: + return _typeName.equals(type._typeName); + + case TypeClass.STRUCT_value: + // This check exploits the fact that an instantiated polymorphic + // struct type may not be the direct base of a struct type: + if (_typeName.indexOf('<') >= 0 || type._typeName.indexOf('<') >= 0) + { + return _typeName.equals(type._typeName); + } + // fall-through + case TypeClass.EXCEPTION_value: + case TypeClass.INTERFACE_value: + Class c1 = getZClass(); + Class c2 = type.getZClass(); + return c1 != null && c2 != null && c1.isAssignableFrom(c2); + + default: + return true; + } + } + + /** + * Indicates whether some other object is equal to this one. + * + * @param obj the reference object with which to compare. + * @return true if this object is the same as the obj argument; + * false otherwise. + * @see java.lang.Object#equals + */ + @Override + public boolean equals(Object obj) { + return obj instanceof Type + && _typeClass == ((Type) obj)._typeClass + && _typeName.equals(((Type) obj)._typeName); + } + + /** + * Returns a hash code value for the object. + * + * @return a hash code value for this object. + * @see java.lang.Object#hashCode + */ + @Override + public int hashCode() { + return _typeName.hashCode(); + } + + /** + * Returns a string representation of the object. + * + * @return a string representation of the object. + * @see java.lang.Object#toString + */ + @Override + public String toString() { + return "Type[" + _typeName + "]"; + } + + private void init( + String name, Class zClass, boolean alternative, boolean arguments, + boolean sequenceComponentType) + { + TypeInfo info = __javaClassToTypeClass.get(zClass); + if (info != null) { + if (sequenceComponentType && !info.sequenceComponentType) { + throw new IllegalArgumentException( + zClass + " cannot be sequence component type"); + } + // info only contains primitive type classes, except for + // TypeClass.INTERFACE, which stands for XInterface (the alternative + // interpretation of java.lang.Object): + _typeClass = alternative ? info.alternative : info.primary; + _typeName = _typeClass == TypeClass.INTERFACE + ? XInterface.class.getName() + : __typeClassToTypeName[_typeClass.getValue()]; + // do not assign _class from zClass, as _class should always be + // normalized (e.g., boolean.class instead of + // java.lang.Boolean.class); getZClass will later calculate the + // correct class when needed + } else if (zClass.isArray()) { + Type t = new Type(zClass.getComponentType(), alternative, true); + _typeClass = t.getTypeClass() != TypeClass.UNKNOWN + ? TypeClass.SEQUENCE : TypeClass.UNKNOWN; + _typeName = "[]" + t.getTypeName(); + // do not assign _class from zClass, as _class should always be + // normalized (e.g., boolean[].class instead of + // java.lang.Boolean[].class); getZClass will later calculate the + // correct class when needed + } else if (Enum.class.isAssignableFrom(zClass)) { + _typeClass = zClass != Enum.class + ? TypeClass.ENUM : TypeClass.UNKNOWN; + _typeName = zClass.getName(); + _class = zClass; + } else if (Throwable.class.isAssignableFrom(zClass)) { + _typeClass + = com.sun.star.uno.Exception.class.isAssignableFrom(zClass) + || com.sun.star.uno.RuntimeException.class.isAssignableFrom( + zClass) + ? TypeClass.EXCEPTION : TypeClass.UNKNOWN; + _typeName = zClass.getName(); + _class = zClass; + } else if (zClass.isInterface()) { + _typeClass = XInterface.class.isAssignableFrom(zClass) + ? TypeClass.INTERFACE : TypeClass.UNKNOWN; + _typeName = zClass.getName(); + _class = zClass; + } else if (XInterface.class.isAssignableFrom(zClass)) { + // This case is needed by code that uses this constructor to + // calculate the UNO type corresponding to a Java object: + _typeClass = TypeClass.INTERFACE; + _typeName = XInterface.class.getName(); + _class = XInterface.class; + } else { + // assert zClass != Object.class && !zClass.isPrimitive(); + _typeClass = TypeClass.STRUCT; + _typeName = name == null ? zClass.getName() : name; + _class = zClass; + } + if (arguments && _typeClass != TypeClass.STRUCT) { + throw new IllegalArgumentException( + zClass + " cannot have type arguments"); + } + } + + private Class determineClass() { + switch (_typeClass.getValue()) { + case TypeClass.VOID_value: + return _typeName.equals(TYPE_NAME_VOID) ? void.class : null; + + case TypeClass.BOOLEAN_value: + return _typeName.equals(TYPE_NAME_BOOLEAN) ? boolean.class : null; + + case TypeClass.BYTE_value: + return _typeName.equals(TYPE_NAME_BYTE) ? byte.class : null; + + case TypeClass.SHORT_value: + return _typeName.equals(TYPE_NAME_SHORT) ? short.class : null; + + case TypeClass.UNSIGNED_SHORT_value: + return _typeName.equals(TYPE_NAME_UNSIGNED_SHORT) + ? short.class : null; + + case TypeClass.LONG_value: + return _typeName.equals(TYPE_NAME_LONG) ? int.class : null; + + case TypeClass.UNSIGNED_LONG_value: + return _typeName.equals(TYPE_NAME_UNSIGNED_LONG) ? int.class : null; + + case TypeClass.HYPER_value: + return _typeName.equals(TYPE_NAME_HYPER) ? long.class : null; + + case TypeClass.UNSIGNED_HYPER_value: + return _typeName.equals(TYPE_NAME_UNSIGNED_HYPER) + ? long.class : null; + + case TypeClass.FLOAT_value: + return _typeName.equals(TYPE_NAME_FLOAT) ? float.class : null; + + case TypeClass.DOUBLE_value: + return _typeName.equals(TYPE_NAME_DOUBLE) ? double.class : null; + + case TypeClass.CHAR_value: + return _typeName.equals(TYPE_NAME_CHAR) ? char.class : null; + + case TypeClass.STRING_value: + return _typeName.equals(TYPE_NAME_STRING) ? String.class : null; + + case TypeClass.TYPE_value: + return _typeName.equals(TYPE_NAME_TYPE) ? Type.class : null; + + case TypeClass.ANY_value: + return _typeName.equals(TYPE_NAME_ANY) ? Object.class : null; + + case TypeClass.SEQUENCE_value: + StringBuffer buf = new StringBuffer(); + int offset = 0; + for (; _typeName.startsWith("[]", offset); offset += "[]".length()) + { + buf.append('['); + } + if (buf.length() == 0) { + return null; + } + String base = _typeName.substring(offset); + if (base.equals(TYPE_NAME_VOID)) { + buf.append('V'); + } else if (base.equals(TYPE_NAME_BOOLEAN)) { + buf.append('Z'); + } else if (base.equals(TYPE_NAME_BYTE)) { + buf.append('B'); + } else if (base.equals(TYPE_NAME_SHORT) + || base.equals(TYPE_NAME_UNSIGNED_SHORT)) { + buf.append('S'); + } else if (base.equals(TYPE_NAME_LONG) + || base.equals(TYPE_NAME_UNSIGNED_LONG)) { + buf.append('I'); + } else if (base.equals(TYPE_NAME_HYPER) + || base.equals(TYPE_NAME_UNSIGNED_HYPER)) { + buf.append('J'); + } else if (base.equals(TYPE_NAME_FLOAT)) { + buf.append('F'); + } else if (base.equals(TYPE_NAME_DOUBLE)) { + buf.append('D'); + } else if (base.equals(TYPE_NAME_CHAR)) { + buf.append('C'); + } else if (base.equals(TYPE_NAME_STRING)) { + buf.append("Ljava.lang.String;"); + } else if (base.equals(TYPE_NAME_TYPE)) { + buf.append("Lcom.sun.star.uno.Type;"); + } else if (base.equals(TYPE_NAME_ANY)) { + buf.append("Ljava.lang.Object;"); + } else { + int args = base.indexOf('<'); + if (args >= 0) { + base = base.substring(0, args); + } + Class c; + try { + c = Class.forName(base); + } catch (ClassNotFoundException e) { + return null; + } + if (args < 0 && new Type(c).getTypeClass() == TypeClass.UNKNOWN) + { + return null; + } + buf.append('L'); + buf.append(base); + buf.append(';'); + } + try { + return Class.forName(buf.toString()); + } catch (ClassNotFoundException e) { + return null; + } + + case TypeClass.ENUM_value: + case TypeClass.EXCEPTION_value: + case TypeClass.INTERFACE_value: + { + Class c; + try { + c = Class.forName(_typeName); + } catch (ClassNotFoundException e) { + return null; + } + return new Type(c).equals(this) ? c : null; + } + + case TypeClass.STRUCT_value: + { + int args = _typeName.indexOf('<'); + Class c; + try { + c = Class.forName( + args < 0 ? _typeName : _typeName.substring(0, args)); + } catch (ClassNotFoundException e) { + return null; + } + return args >= 0 || new Type(c).equals(this) ? c : null; + } + + default: + return null; + } + } + + private static boolean __isTypeClassPrimitive(TypeClass typeClass) { + return typeClass.getValue() < __typeClassToTypeName.length; + } + + private TypeClass _typeClass; // TODO should be final + private String _typeName; // TODO should be final + + private Class _class; + private TypeDescription _iTypeDescription; +} -- cgit v1.2.3