com.sun.star.lib.uno.protocols.urp.Unmarshal Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of libreoffice Show documentation
Show all versions of libreoffice Show documentation
Public UNO Java Classes (formerly jurt,juh,ridl,unoil)
/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* 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.lib.uno.protocols.urp;
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;
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.Type;
import com.sun.star.uno.TypeClass;
import com.sun.star.uno.XInterface;
import com.sun.star.lib.uno.typedesc.FieldDescription;
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);
}
}
public int read16Bit() {
try {
return input.readUnsignedShort();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public String readObjectId() {
try {
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;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public Object readInterface(Type type) {
String id = readObjectId();
return id == null ? null : bridge.mapInterfaceFrom(id, type);
}
public ThreadId readThreadId() {
try {
int len = readCompressedNumber();
byte[] data ;
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;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public TypeDescription readType() {
int b = read8Bit();
TypeClass typeClass = TypeClass.fromInt(b & 0x7F);
if (typeClass == null) {
throw new RuntimeException(
"Reading TYPE with bad type class " + (b & 0x7F));
}
if (TypeDescription.isTypeClassSimple(typeClass)) {
if ((b & 0x80) != 0) {
throw new RuntimeException(
"Reading TYPE with bad type class/cache flag " + b);
}
return TypeDescription.getTypeDescription(typeClass);
} else {
int index = read16Bit();
TypeDescription type;
if ((b & 0x80) == 0) {
if (index >= typeCache.length) {
throw new RuntimeException(
"Reading TYPE with bad cache index " + index);
}
type = typeCache[index];
if (type == null) {
throw new RuntimeException(
"Reading TYPE with empty cache index " + index);
}
} else {
try {
type = TypeDescription.getTypeDescription(
readStringValue());
} catch (IOException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
if (index != 0xFFFF) {
if (index >= typeCache.length) {
throw new RuntimeException(
"Reading TYPE with bad cache index " + index);
}
typeCache[index] = type;
}
}
return type;
}
}
public Object readValue(TypeDescription type) {
try {
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);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public boolean hasMore() {
try {
return input.available() > 0;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void reset(byte[] data) {
input = new DataInputStream(new ByteArrayInputStream(data));
}
private Boolean readBooleanValue() throws IOException {
return input.readBoolean() ? Boolean.TRUE : Boolean.FALSE;
}
private Byte readByteValue() throws IOException {
return Byte.valueOf(input.readByte());
}
private Short readShortValue() throws IOException {
return Short.valueOf(input.readShort());
}
private Integer readLongValue() throws IOException {
return Integer.valueOf(input.readInt());
}
private Long readHyperValue() throws IOException {
return Long.valueOf(input.readLong());
}
private Float readFloatValue() throws IOException {
return Float.valueOf(input.readFloat());
}
private Double readDoubleValue() throws IOException {
return Double.valueOf(input.readDouble());
}
private Character readCharValue() throws IOException {
return Character.valueOf(input.readChar());
}
private String readStringValue() throws IOException {
int len = readCompressedNumber();
byte[] data = new byte[len];
readBytes(data);
try {
return new String(data, "UTF8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
private Type readTypeValue() {
return new Type(readType());
}
private Object readAnyValue() throws IOException {
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 = type.getComponentType();
while (ctype.getTypeClass() == TypeClass.SEQUENCE) {
ctype = 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) throws IOException {
int len = readCompressedNumber();
TypeDescription ctype = 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) throws IOException {
try {
return (Enum)
type.getZClass().getMethod(
"fromInt", new Class[] { int.class }).
invoke(null, new Object[] { readLongValue() });
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
private Object readStructValue(TypeDescription type) {
Object value;
try {
value = type.getZClass().newInstance();
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
}
readFields(type, value);
return value;
}
private Exception readExceptionValue(TypeDescription type) throws IOException {
Exception value;
try {
value = (Exception)
type.getZClass().getConstructor(new Class[] { String.class }).
newInstance(new Object[] { readStringValue() });
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
readFields(type, value);
return value;
}
private Object readInterfaceValue(TypeDescription type) {
return readInterface(new Type(type));
}
private int readCompressedNumber() throws IOException {
int number = read8Bit();
return number < 0xFF ? number : input.readInt();
}
private void readBytes(byte[] data) throws IOException {
input.readFully(data);
}
private void readFields(TypeDescription type, Object value) {
FieldDescription[] fields = type.getFieldDescriptions();
for (int i = 0; i < fields.length; ++i) {
try {
fields[i].getField().set(
value,
readValue(
fields[i].getTypeDescription()));
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
private final IBridge bridge;
private final String[] objectIdCache;
private final ThreadId[] threadIdCache;
private final TypeDescription[] typeCache;
private DataInputStream input;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */