00e1ac51e6
replace with Character.valueOf Change-Id: I9938db0fce6490eba6f4900efc3c139a1b71d120 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158786 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
476 lines
15 KiB
Java
476 lines
15 KiB
Java
/* -*- 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: */
|