1 /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
19 package com
.sun
.star
.lib
.uno
.protocols
.urp
;
21 import java
.io
.ByteArrayInputStream
;
22 import java
.io
.DataInputStream
;
23 import java
.io
.IOException
;
24 import java
.io
.UnsupportedEncodingException
;
25 import java
.lang
.reflect
.Array
;
26 import java
.lang
.reflect
.InvocationTargetException
;
28 import com
.sun
.star
.lib
.uno
.environments
.remote
.ThreadId
;
29 import com
.sun
.star
.lib
.uno
.typedesc
.TypeDescription
;
30 import com
.sun
.star
.uno
.Any
;
31 import com
.sun
.star
.uno
.Enum
;
32 import com
.sun
.star
.uno
.IBridge
;
33 import com
.sun
.star
.uno
.Type
;
34 import com
.sun
.star
.uno
.TypeClass
;
35 import com
.sun
.star
.uno
.XInterface
;
36 import com
.sun
.star
.lib
.uno
.typedesc
.FieldDescription
;
38 final class Unmarshal
{
39 public Unmarshal(IBridge bridge
, int cacheSize
) {
41 objectIdCache
= new String
[cacheSize
];
42 threadIdCache
= new ThreadId
[cacheSize
];
43 typeCache
= new TypeDescription
[cacheSize
];
47 public int read8Bit() {
49 return input
.readUnsignedByte();
50 } catch (IOException e
) {
51 throw new RuntimeException(e
);
55 public int read16Bit() {
57 return input
.readUnsignedShort();
58 } catch (IOException e
) {
59 throw new RuntimeException(e
);
63 public String
readObjectId() {
65 String id
= readStringValue();
66 int index
= read16Bit();
67 if (index
== 0xFFFF) {
68 if (id
.length() == 0) {
72 if (id
.length() == 0) {
73 id
= objectIdCache
[index
];
75 objectIdCache
[index
] = id
;
79 } catch (IOException e
) {
80 throw new RuntimeException(e
);
84 public Object
readInterface(Type type
) {
85 String id
= readObjectId();
86 return id
== null ?
null : bridge
.mapInterfaceFrom(id
, type
);
89 public ThreadId
readThreadId() {
91 int len
= readCompressedNumber();
97 id
= new ThreadId(data
);
99 int index
= read16Bit();
100 if (index
!= 0xFFFF) {
102 id
= threadIdCache
[index
];
104 threadIdCache
[index
] = id
;
108 } catch (IOException e
) {
109 throw new RuntimeException(e
);
113 public TypeDescription
readType() {
115 TypeClass typeClass
= TypeClass
.fromInt(b
& 0x7F);
116 if (typeClass
== null) {
117 throw new RuntimeException(
118 "Reading TYPE with bad type class " + (b
& 0x7F));
120 if (TypeDescription
.isTypeClassSimple(typeClass
)) {
121 if ((b
& 0x80) != 0) {
122 throw new RuntimeException(
123 "Reading TYPE with bad type class/cache flag " + b
);
125 return TypeDescription
.getTypeDescription(typeClass
);
127 int index
= read16Bit();
128 TypeDescription type
;
129 if ((b
& 0x80) == 0) {
130 if (index
>= typeCache
.length
) {
131 throw new RuntimeException(
132 "Reading TYPE with bad cache index " + index
);
134 type
= typeCache
[index
];
136 throw new RuntimeException(
137 "Reading TYPE with empty cache index " + index
);
141 type
= TypeDescription
.getTypeDescription(
143 } catch (IOException e
) {
144 throw new RuntimeException(e
);
145 } catch (ClassNotFoundException e
) {
146 throw new RuntimeException(e
);
148 if (index
!= 0xFFFF) {
149 if (index
>= typeCache
.length
) {
150 throw new RuntimeException(
151 "Reading TYPE with bad cache index " + index
);
153 typeCache
[index
] = type
;
160 public Object
readValue(TypeDescription type
) {
162 switch (type
.getTypeClass().getValue()) {
163 case TypeClass
.VOID_value
:
166 case TypeClass
.BOOLEAN_value
:
167 return readBooleanValue();
169 case TypeClass
.BYTE_value
:
170 return readByteValue();
172 case TypeClass
.SHORT_value
:
173 case TypeClass
.UNSIGNED_SHORT_value
:
174 return readShortValue();
176 case TypeClass
.LONG_value
:
177 case TypeClass
.UNSIGNED_LONG_value
:
178 return readLongValue();
180 case TypeClass
.HYPER_value
:
181 case TypeClass
.UNSIGNED_HYPER_value
:
182 return readHyperValue();
184 case TypeClass
.FLOAT_value
:
185 return readFloatValue();
187 case TypeClass
.DOUBLE_value
:
188 return readDoubleValue();
190 case TypeClass
.CHAR_value
:
191 return readCharValue();
193 case TypeClass
.STRING_value
:
194 return readStringValue();
196 case TypeClass
.TYPE_value
:
197 return readTypeValue();
199 case TypeClass
.ANY_value
:
200 return readAnyValue();
202 case TypeClass
.SEQUENCE_value
:
203 return readSequenceValue(type
);
205 case TypeClass
.ENUM_value
:
206 return readEnumValue(type
);
208 case TypeClass
.STRUCT_value
:
209 return readStructValue(type
);
211 case TypeClass
.EXCEPTION_value
:
212 return readExceptionValue(type
);
214 case TypeClass
.INTERFACE_value
:
215 return readInterfaceValue(type
);
218 throw new IllegalArgumentException("Bad type descriptor " + type
);
220 } catch (IOException e
) {
221 throw new RuntimeException(e
);
225 public boolean hasMore() {
227 return input
.available() > 0;
228 } catch (IOException e
) {
229 throw new RuntimeException(e
);
233 public void reset(byte[] data
) {
234 input
= new DataInputStream(new ByteArrayInputStream(data
));
237 private Boolean
readBooleanValue() throws IOException
{
238 return input
.readBoolean() ? Boolean
.TRUE
: Boolean
.FALSE
;
241 private Byte
readByteValue() throws IOException
{
242 return Byte
.valueOf(input
.readByte());
245 private Short
readShortValue() throws IOException
{
246 return Short
.valueOf(input
.readShort());
249 private Integer
readLongValue() throws IOException
{
250 return Integer
.valueOf(input
.readInt());
253 private Long
readHyperValue() throws IOException
{
254 return Long
.valueOf(input
.readLong());
257 private Float
readFloatValue() throws IOException
{
258 return new Float(input
.readFloat());
261 private Double
readDoubleValue() throws IOException
{
262 return new Double(input
.readDouble());
265 private Character
readCharValue() throws IOException
{
266 return new Character(input
.readChar());
269 private String
readStringValue() throws IOException
{
270 int len
= readCompressedNumber();
271 byte[] data
= new byte[len
];
274 return new String(data
, "UTF8");
275 } catch (UnsupportedEncodingException e
) {
276 throw new RuntimeException(e
);
280 private Type
readTypeValue() {
281 return new Type(readType());
284 private Object
readAnyValue() throws IOException
{
285 TypeDescription type
= readType();
286 switch (type
.getTypeClass().getValue()) {
287 case TypeClass
.VOID_value
:
290 case TypeClass
.BOOLEAN_value
:
291 return readBooleanValue();
293 case TypeClass
.BYTE_value
:
294 return readByteValue();
296 case TypeClass
.SHORT_value
:
297 return readShortValue();
299 case TypeClass
.UNSIGNED_SHORT_value
:
300 return new Any(Type
.UNSIGNED_SHORT
, readShortValue());
302 case TypeClass
.LONG_value
:
303 return readLongValue();
305 case TypeClass
.UNSIGNED_LONG_value
:
306 return new Any(Type
.UNSIGNED_LONG
, readLongValue());
308 case TypeClass
.HYPER_value
:
309 return readHyperValue();
311 case TypeClass
.UNSIGNED_HYPER_value
:
312 return new Any(Type
.UNSIGNED_HYPER
, readHyperValue());
314 case TypeClass
.FLOAT_value
:
315 return readFloatValue();
317 case TypeClass
.DOUBLE_value
:
318 return readDoubleValue();
320 case TypeClass
.CHAR_value
:
321 return readCharValue();
323 case TypeClass
.STRING_value
:
324 return readStringValue();
326 case TypeClass
.TYPE_value
:
327 return readTypeValue();
329 case TypeClass
.SEQUENCE_value
:
331 Object value
= readSequenceValue(type
);
332 TypeDescription ctype
= type
.getComponentType();
333 while (ctype
.getTypeClass() == TypeClass
.SEQUENCE
) {
334 ctype
= ctype
.getComponentType();
336 switch (ctype
.getTypeClass().getValue()) {
337 case TypeClass
.UNSIGNED_SHORT_value
:
338 case TypeClass
.UNSIGNED_LONG_value
:
339 case TypeClass
.UNSIGNED_HYPER_value
:
340 return new Any(new Type(type
), value
);
342 case TypeClass
.STRUCT_value
:
343 if (ctype
.hasTypeArguments()) {
344 return new Any(new Type(type
), value
);
351 case TypeClass
.ENUM_value
:
352 return readEnumValue(type
);
354 case TypeClass
.STRUCT_value
:
356 Object value
= readStructValue(type
);
357 return type
.hasTypeArguments()
358 ?
new Any(new Type(type
), value
) : value
;
361 case TypeClass
.EXCEPTION_value
:
362 return readExceptionValue(type
);
364 case TypeClass
.INTERFACE_value
:
366 Object value
= readInterfaceValue(type
);
367 return type
.getZClass() == XInterface
.class
368 ? value
: new Any(new Type(type
), value
);
372 throw new RuntimeException(
373 "Reading ANY with bad type " + type
.getTypeClass());
377 private Object
readSequenceValue(TypeDescription type
) throws IOException
{
378 int len
= readCompressedNumber();
379 TypeDescription ctype
= type
.getComponentType();
380 if (ctype
.getTypeClass() == TypeClass
.BYTE
) {
381 byte[] data
= new byte[len
];
385 Object value
= Array
.newInstance(
386 ctype
.getTypeClass() == TypeClass
.ANY
387 ? Object
.class : ctype
.getZClass(), len
);
388 for (int i
= 0; i
< len
; ++i
) {
389 Array
.set(value
, i
, readValue(ctype
));
395 private Enum
readEnumValue(TypeDescription type
) throws IOException
{
398 type
.getZClass().getMethod(
399 "fromInt", new Class
[] { int.class }).
400 invoke(null, new Object
[] { readLongValue() });
401 } catch (IllegalAccessException e
) {
402 throw new RuntimeException(e
);
403 } catch (InvocationTargetException e
) {
404 throw new RuntimeException(e
);
405 } catch (NoSuchMethodException e
) {
406 throw new RuntimeException(e
);
410 private Object
readStructValue(TypeDescription type
) {
413 value
= type
.getZClass().newInstance();
414 } catch (IllegalAccessException e
) {
415 throw new RuntimeException(e
);
416 } catch (InstantiationException e
) {
417 throw new RuntimeException(e
);
419 readFields(type
, value
);
423 private Exception
readExceptionValue(TypeDescription type
) throws IOException
{
427 type
.getZClass().getConstructor(new Class
[] { String
.class }).
428 newInstance(new Object
[] { readStringValue() });
429 } catch (IllegalAccessException e
) {
430 throw new RuntimeException(e
);
431 } catch (InstantiationException e
) {
432 throw new RuntimeException(e
);
433 } catch (InvocationTargetException e
) {
434 throw new RuntimeException(e
);
435 } catch (NoSuchMethodException e
) {
436 throw new RuntimeException(e
);
438 readFields(type
, value
);
442 private Object
readInterfaceValue(TypeDescription type
) {
443 return readInterface(new Type(type
));
446 private int readCompressedNumber() throws IOException
{
447 int number
= read8Bit();
448 return number
< 0xFF ? number
: input
.readInt();
451 private void readBytes(byte[] data
) throws IOException
{
452 input
.readFully(data
);
455 private void readFields(TypeDescription type
, Object value
) {
456 FieldDescription
[] fields
= type
.getFieldDescriptions();
457 for (int i
= 0; i
< fields
.length
; ++i
) {
459 fields
[i
].getField().set(
462 fields
[i
].getTypeDescription()));
463 } catch (IllegalAccessException e
) {
464 throw new RuntimeException(e
);
469 private final IBridge bridge
;
470 private final String
[] objectIdCache
;
471 private final ThreadId
[] threadIdCache
;
472 private final TypeDescription
[] typeCache
;
473 private DataInputStream input
;
476 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */