diff options
Diffstat (limited to 'jurt/com/sun/star/lib/uno/protocols/urp/Unmarshal.java')
-rw-r--r-- | jurt/com/sun/star/lib/uno/protocols/urp/Unmarshal.java | 490 |
1 files changed, 490 insertions, 0 deletions
diff --git a/jurt/com/sun/star/lib/uno/protocols/urp/Unmarshal.java b/jurt/com/sun/star/lib/uno/protocols/urp/Unmarshal.java new file mode 100644 index 000000000000..5a500ad3a0c1 --- /dev/null +++ b/jurt/com/sun/star/lib/uno/protocols/urp/Unmarshal.java @@ -0,0 +1,490 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +package com.sun.star.lib.uno.protocols.urp; + +import com.sun.star.lib.uno.environments.remote.ThreadId; +import com.sun.star.lib.uno.typedesc.TypeDescription; +import com.sun.star.uno.Any; +import com.sun.star.uno.Enum; +import com.sun.star.uno.IBridge; +import com.sun.star.uno.IFieldDescription; +import com.sun.star.uno.Type; +import com.sun.star.uno.TypeClass; +import com.sun.star.uno.XInterface; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; + +final class Unmarshal { + public Unmarshal(IBridge bridge, int cacheSize) { + this.bridge = bridge; + objectIdCache = new String[cacheSize]; + threadIdCache = new ThreadId[cacheSize]; + typeCache = new TypeDescription[cacheSize]; + reset(new byte[0]); + } + + public int read8Bit() { + try { + return input.readUnsignedByte(); + } catch (IOException e) { + throw new RuntimeException(e.toString()); + } + } + + public int read16Bit() { + try { + return input.readUnsignedShort(); + } catch (IOException e) { + throw new RuntimeException(e.toString()); + } + } + + public String readObjectId() { + String id = readStringValue(); + int index = read16Bit(); + if (index == 0xFFFF) { + if (id.length() == 0) { + id = null; + } + } else { + if (id.length() == 0) { + id = objectIdCache[index]; + } else { + objectIdCache[index] = id; + } + } + return id; + } + + public Object readInterface(Type type) { + String id = readObjectId(); + return id == null ? null : bridge.mapInterfaceFrom(id, type); + } + + public ThreadId readThreadId() { + int len = readCompressedNumber(); + byte[] data = null; + ThreadId id = null; + if (len != 0) { + data = new byte[len]; + readBytes(data); + id = new ThreadId(data); + } + int index = read16Bit(); + if (index != 0xFFFF) { + if (len == 0) { + id = threadIdCache[index]; + } else { + threadIdCache[index] = id; + } + } + return id; + } + + public TypeDescription readType() { + int b = read8Bit(); + TypeClass typeClass = TypeClass.fromInt(b & 0x7F); + if (TypeDescription.isTypeClassSimple(typeClass)) { + return TypeDescription.getTypeDescription(typeClass); + } else { + int index = read16Bit(); + TypeDescription type = null; + if ((b & 0x80) != 0) { + try { + type = TypeDescription.getTypeDescription( + readStringValue()); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e.toString()); + } + } + if (index != 0xFFFF) { + if ((b & 0x80) == 0) { + type = typeCache[index]; + } else { + typeCache[index] = type; + } + } + return type; + } + } + + public Object readValue(TypeDescription type) { + switch (type.getTypeClass().getValue()) { + case TypeClass.VOID_value: + return null; + + case TypeClass.BOOLEAN_value: + return readBooleanValue(); + + case TypeClass.BYTE_value: + return readByteValue(); + + case TypeClass.SHORT_value: + case TypeClass.UNSIGNED_SHORT_value: + return readShortValue(); + + case TypeClass.LONG_value: + case TypeClass.UNSIGNED_LONG_value: + return readLongValue(); + + case TypeClass.HYPER_value: + case TypeClass.UNSIGNED_HYPER_value: + return readHyperValue(); + + case TypeClass.FLOAT_value: + return readFloatValue(); + + case TypeClass.DOUBLE_value: + return readDoubleValue(); + + case TypeClass.CHAR_value: + return readCharValue(); + + case TypeClass.STRING_value: + return readStringValue(); + + case TypeClass.TYPE_value: + return readTypeValue(); + + case TypeClass.ANY_value: + return readAnyValue(); + + case TypeClass.SEQUENCE_value: + return readSequenceValue(type); + + case TypeClass.ENUM_value: + return readEnumValue(type); + + case TypeClass.STRUCT_value: + return readStructValue(type); + + case TypeClass.EXCEPTION_value: + return readExceptionValue(type); + + case TypeClass.INTERFACE_value: + return readInterfaceValue(type); + + default: + throw new IllegalArgumentException("Bad type descriptor " + type); + } + } + + public boolean hasMore() { + try { + return input.available() > 0; + } catch (IOException e) { + throw new RuntimeException(e.toString()); + } + } + + public void reset(byte[] data) { + input = new DataInputStream(new ByteArrayInputStream(data)); + } + + private Boolean readBooleanValue() { + try { + return input.readBoolean() ? Boolean.TRUE : Boolean.FALSE; + } catch (IOException e) { + throw new RuntimeException(e.toString()); + } + } + + private Byte readByteValue() { + try { + return new Byte(input.readByte()); + } catch (IOException e) { + throw new RuntimeException(e.toString()); + } + } + + private Short readShortValue() { + try { + return new Short(input.readShort()); + } catch (IOException e) { + throw new RuntimeException(e.toString()); + } + } + + private Integer readLongValue() { + try { + return new Integer(input.readInt()); + } catch (IOException e) { + throw new RuntimeException(e.toString()); + } + } + + private Long readHyperValue() { + try { + return new Long(input.readLong()); + } catch (IOException e) { + throw new RuntimeException(e.toString()); + } + } + + private Float readFloatValue() { + try { + return new Float(input.readFloat()); + } catch (IOException e) { + throw new RuntimeException(e.toString()); + } + } + + private Double readDoubleValue() { + try { + return new Double(input.readDouble()); + } catch (IOException e) { + throw new RuntimeException(e.toString()); + } + } + + private Character readCharValue() { + try { + return new Character(input.readChar()); + } catch (IOException e) { + throw new RuntimeException(e.toString()); + } + } + + private String readStringValue() { + int len = readCompressedNumber(); + byte[] data = new byte[len]; + readBytes(data); + try { + return new String(data, "UTF8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e.toString()); + } + } + + private Type readTypeValue() { + return new Type(readType()); + } + + private Object readAnyValue() { + TypeDescription type = readType(); + switch (type.getTypeClass().getValue()) { + case TypeClass.VOID_value: + return Any.VOID; + + case TypeClass.BOOLEAN_value: + return readBooleanValue(); + + case TypeClass.BYTE_value: + return readByteValue(); + + case TypeClass.SHORT_value: + return readShortValue(); + + case TypeClass.UNSIGNED_SHORT_value: + return new Any(Type.UNSIGNED_SHORT, readShortValue()); + + case TypeClass.LONG_value: + return readLongValue(); + + case TypeClass.UNSIGNED_LONG_value: + return new Any(Type.UNSIGNED_LONG, readLongValue()); + + case TypeClass.HYPER_value: + return readHyperValue(); + + case TypeClass.UNSIGNED_HYPER_value: + return new Any(Type.UNSIGNED_HYPER, readHyperValue()); + + case TypeClass.FLOAT_value: + return readFloatValue(); + + case TypeClass.DOUBLE_value: + return readDoubleValue(); + + case TypeClass.CHAR_value: + return readCharValue(); + + case TypeClass.STRING_value: + return readStringValue(); + + case TypeClass.TYPE_value: + return readTypeValue(); + + case TypeClass.SEQUENCE_value: + { + Object value = readSequenceValue(type); + TypeDescription ctype = (TypeDescription) + type.getComponentType(); + while (ctype.getTypeClass() == TypeClass.SEQUENCE) { + ctype = (TypeDescription) ctype.getComponentType(); + } + switch (ctype.getTypeClass().getValue()) { + case TypeClass.UNSIGNED_SHORT_value: + case TypeClass.UNSIGNED_LONG_value: + case TypeClass.UNSIGNED_HYPER_value: + return new Any(new Type(type), value); + + case TypeClass.STRUCT_value: + if (ctype.hasTypeArguments()) { + return new Any(new Type(type), value); + } + default: + return value; + } + } + + case TypeClass.ENUM_value: + return readEnumValue(type); + + case TypeClass.STRUCT_value: + { + Object value = readStructValue(type); + return type.hasTypeArguments() + ? new Any(new Type(type), value) : value; + } + + case TypeClass.EXCEPTION_value: + return readExceptionValue(type); + + case TypeClass.INTERFACE_value: + { + Object value = readInterfaceValue(type); + return type.getZClass() == XInterface.class + ? value : new Any(new Type(type), value); + } + + default: + throw new RuntimeException( + "Reading ANY with bad type " + type.getTypeClass()); + } + } + + private Object readSequenceValue(TypeDescription type) { + int len = readCompressedNumber(); + TypeDescription ctype = (TypeDescription) type.getComponentType(); + if (ctype.getTypeClass() == TypeClass.BYTE) { + byte[] data = new byte[len]; + readBytes(data); + return data; + } else { + Object value = Array.newInstance( + ctype.getTypeClass() == TypeClass.ANY + ? Object.class : ctype.getZClass(), len); + for (int i = 0; i < len; ++i) { + Array.set(value, i, readValue(ctype)); + } + return value; + } + } + + private Enum readEnumValue(TypeDescription type) { + try { + return (Enum) + type.getZClass().getMethod( + "fromInt", new Class[] { int.class }). + invoke(null, new Object[] { readLongValue() }); + } catch (IllegalAccessException e) { + throw new RuntimeException(e.toString()); + } catch (InvocationTargetException e) { + throw new RuntimeException(e.toString()); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e.toString()); + } + } + + private Object readStructValue(TypeDescription type) { + Object value; + try { + value = type.getZClass().newInstance(); + } catch (IllegalAccessException e) { + throw new RuntimeException(e.toString()); + } catch (InstantiationException e) { + throw new RuntimeException(e.toString()); + } + readFields(type, value); + return value; + } + + private Exception readExceptionValue(TypeDescription type) { + Exception value; + try { + value = (Exception) + type.getZClass().getConstructor(new Class[] { String.class }). + newInstance(new Object[] { readStringValue() }); + } catch (IllegalAccessException e) { + throw new RuntimeException(e.toString()); + } catch (InstantiationException e) { + throw new RuntimeException(e.toString()); + } catch (InvocationTargetException e) { + throw new RuntimeException(e.toString()); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e.toString()); + } + readFields(type, value); + return value; + } + + private Object readInterfaceValue(TypeDescription type) { + return readInterface(new Type(type)); + } + + private int readCompressedNumber() { + int number = read8Bit(); + try { + return number < 0xFF ? number : input.readInt(); + } catch (IOException e) { + throw new RuntimeException(e.toString()); + } + } + + private void readBytes(byte[] data) { + try { + input.readFully(data); + } catch (IOException e) { + throw new RuntimeException(e.toString()); + } + } + + private void readFields(TypeDescription type, Object value) { + IFieldDescription[] fields = type.getFieldDescriptions(); + for (int i = 0; i < fields.length; ++i) { + try { + fields[i].getField().set( + value, + readValue( + (TypeDescription) fields[i].getTypeDescription())); + } catch (IllegalAccessException e) { + throw new RuntimeException(e.toString()); + } + } + } + + private final IBridge bridge; + private final String[] objectIdCache; + private final ThreadId[] threadIdCache; + private final TypeDescription[] typeCache; + private DataInputStream input; +} |