All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.star.lib.uno.protocols.urp.Marshal Maven / Gradle / Ivy

There is a newer version: 24.2.3
Show newest version
/* -*- 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.ByteArrayOutputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
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.FieldDescription;
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;

final class Marshal {
    public Marshal(IBridge bridge, short cacheSize) {
        this.bridge = bridge;
        objectIdCache = new Cache(cacheSize);
        threadIdCache = new Cache(cacheSize);
        typeCache = new Cache(cacheSize);
    }

    public void write8Bit(int value) {
        try {
            output.writeByte(value);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public void write16Bit(int value) {
        try {
            output.writeShort(value);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public void writeObjectId(String objectId) {
        try {
            if (objectId == null) {
                writeStringValue(null);
                write16Bit(0xFFFF);
            } else {
                boolean[] found = new boolean[1];
                int index = objectIdCache.add(found, objectId);
                writeStringValue(found[0] ? null : objectId);
                write16Bit(index);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public void writeInterface(XInterface object, Type type) {
        writeObjectId((String) bridge.mapInterfaceTo(object, type));
    }

    public void writeThreadId(ThreadId threadId) {
        try {
            byte[] data = threadId.getBytes();
            boolean[] found = new boolean[1];
            int index = threadIdCache.add(found, data);
            if (found[0]) {
                writeCompressedNumber(0);
            } else {
                writeCompressedNumber(data.length);
                writeBytes(data);
            }
            write16Bit(index);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public void writeType(TypeDescription type) {
        try {
            TypeClass typeClass = type.getTypeClass();
            if (TypeDescription.isTypeClassSimple(typeClass)) {
                write8Bit(typeClass.getValue());
            } else {
                boolean[] found = new boolean[1];
                int index = typeCache.add(found, type.getTypeName());
                write8Bit(typeClass.getValue() | (found[0] ? 0 : 0x80));
                write16Bit(index);
                if (!found[0]) {
                    writeStringValue(type.getTypeName());
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public void writeValue(TypeDescription type, Object value) {
        try {
            switch(type.getTypeClass().getValue()) {
            case TypeClass.VOID_value:
                break;

            case TypeClass.BOOLEAN_value:
                writeBooleanValue((Boolean) value);
                break;

            case TypeClass.BYTE_value:
                writeByteValue((Byte) value);
                break;

            case TypeClass.SHORT_value:
            case TypeClass.UNSIGNED_SHORT_value:
                writeShortValue((Short) value);
                break;

            case TypeClass.LONG_value:
            case TypeClass.UNSIGNED_LONG_value:
                writeLongValue((Integer) value);
                break;

            case TypeClass.HYPER_value:
            case TypeClass.UNSIGNED_HYPER_value:
                writeHyperValue((Long) value);
                break;

            case TypeClass.FLOAT_value:
                writeFloatValue((Float) value);
                break;

            case TypeClass.DOUBLE_value:
                writeDoubleValue((Double) value);
                break;

            case TypeClass.CHAR_value:
                writeCharValue((Character) value);
                break;

            case TypeClass.STRING_value:
                writeStringValue((String) value);
                break;

            case TypeClass.TYPE_value:
                writeTypeValue((Type) value);
                break;

            case TypeClass.ANY_value:
                writeAnyValue(value);
                break;

            case TypeClass.SEQUENCE_value:
                writeSequenceValue(type, value);
                break;

            case TypeClass.ENUM_value:
                writeEnumValue(type, (Enum) value);
                break;

            case TypeClass.STRUCT_value:
                writeStructValue(type, value);
                break;

            case TypeClass.EXCEPTION_value:
                writeExceptionValue(type, (Exception) value);
                break;

            case TypeClass.INTERFACE_value:
                writeInterfaceValue(type, (XInterface) value);
                break;

            default:
                throw new IllegalArgumentException("Bad type descriptor " + type);
            }
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    public byte[] reset() {
        byte[] data = buffer.toByteArray();
        buffer.reset();
        return data;
    }

    private void writeBooleanValue(Boolean value) throws IOException {
        output.writeBoolean(value != null && value.booleanValue());
    }

    private void writeByteValue(Byte value) {
        write8Bit(value == null ? 0 : value.byteValue());
    }

    private void writeShortValue(Short value) {
        write16Bit(value == null ? 0 : value.shortValue());
    }

    private void writeLongValue(Integer value) throws IOException {
        write32Bit(value == null ? 0 : value.intValue());
    }

    private void writeHyperValue(Long value) throws IOException {
        output.writeLong(value == null ? 0 : value.longValue());
    }

    private void writeFloatValue(Float value) throws IOException {
        output.writeFloat(value == null ? 0 : value.floatValue());
    }

    private void writeDoubleValue(Double value) throws IOException {
        output.writeDouble(value == null ? 0 : value.doubleValue());
    }

    private void writeCharValue(Character value) throws IOException {
        output.writeChar(value == null ? 0 : value.charValue());
    }

    private void writeStringValue(String value) throws IOException {
        if (value == null) {
            writeCompressedNumber(0);
        } else {
            byte[] data = value.getBytes("UTF8");
            writeCompressedNumber(data.length);
            writeBytes(data);
        }
    }

    private void writeTypeValue(Type value) throws ClassNotFoundException {
        writeType(
            TypeDescription.getTypeDescription(
                value == null ? Type.VOID : value));
    }

    private void writeAnyValue(Object value) throws ClassNotFoundException {
        TypeDescription type;
        if (value == null || value instanceof XInterface) {
            type = TypeDescription.getTypeDescription(XInterface.class);
        } else if (value instanceof Any) {
            Any any = (Any) value;
            type = TypeDescription.getTypeDescription(any.getType());
            value = any.getObject();
        } else if (value.getClass() == Object.class) {
            // Avoid StackOverflowError:
            throw new IllegalArgumentException(
                "Object instance does not represent UNO value");
        } else {
            type = TypeDescription.getTypeDescription(value.getClass());
        }
        writeType(type);
        writeValue(type, value);
    }

    private void writeSequenceValue(TypeDescription type, Object value) throws IOException {
        if (value == null) {
            writeCompressedNumber(0);
        } else {
            TypeDescription ctype = type.getComponentType();
            if (ctype.getTypeClass() == TypeClass.BYTE) {
                byte[] data = (byte[]) value;
                writeCompressedNumber(data.length);
                writeBytes(data);
            } else {
                int len = Array.getLength(value);
                writeCompressedNumber(len);
                for (int i = 0; i < len; ++i) {
                    writeValue(ctype, Array.get(value, i));
                }
            }
        }
    }

    private void writeEnumValue(TypeDescription type, Enum value) throws IllegalAccessException, IOException, InvocationTargetException, NoSuchMethodException {
        int n;
        if (value == null) {
            n = ((Enum)
                 (type.getZClass().getMethod("getDefault", (Class[]) null).
                  invoke(null, (Object[]) null))).
                getValue();
        } else {
            n = value.getValue();
        }
        write32Bit(n);
    }

    private void writeStructValue(TypeDescription type, Object value) throws IllegalAccessException {
        FieldDescription[] fields = type.getFieldDescriptions();
        for (int i = 0; i < fields.length; ++i) {
            writeValue(
                fields[i].getTypeDescription(),
                value == null ? null : fields[i].getField().get(value));
        }
    }

    private void writeExceptionValue(TypeDescription type, Exception value) throws IllegalAccessException, IOException {
        writeStringValue(value == null ? null : value.getMessage());
        writeStructValue(type, value);
    }

    private void writeInterfaceValue(TypeDescription type, XInterface value) {
        writeInterface(value, new Type(type));
    }

    private void write32Bit(int value) throws IOException {
        output.writeInt(value);
    }

    private void writeCompressedNumber(int number) throws IOException {
        if (number >= 0 && number < 0xFF) {
            write8Bit(number);
        } else {
            write8Bit(0xFF);
            write32Bit(number);
        }
    }

    private void writeBytes(byte[] data) throws IOException {
        output.write(data);
    }

    private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    private final DataOutput output = new DataOutputStream(buffer);
    private final IBridge bridge;
    private final Cache objectIdCache;
    private final Cache threadIdCache;
    private final Cache typeCache;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */




© 2015 - 2024 Weber Informatics LLC | Privacy Policy