bump product version to 6.4.0.3
[LibreOffice.git] / jurt / com / sun / star / lib / uno / protocols / urp / Unmarshal.java
blobc16d19291356a0aecab601d7f5911f017573be3d
1 /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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) {
40 this.bridge = bridge;
41 objectIdCache = new String[cacheSize];
42 threadIdCache = new ThreadId[cacheSize];
43 typeCache = new TypeDescription[cacheSize];
44 reset(new byte[0]);
47 public int read8Bit() {
48 try {
49 return input.readUnsignedByte();
50 } catch (IOException e) {
51 throw new RuntimeException(e);
55 public int read16Bit() {
56 try {
57 return input.readUnsignedShort();
58 } catch (IOException e) {
59 throw new RuntimeException(e);
63 public String readObjectId() {
64 try {
65 String id = readStringValue();
66 int index = read16Bit();
67 if (index == 0xFFFF) {
68 if (id.length() == 0) {
69 id = null;
71 } else {
72 if (id.length() == 0) {
73 id = objectIdCache[index];
74 } else {
75 objectIdCache[index] = id;
78 return 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() {
90 try {
91 int len = readCompressedNumber();
92 byte[] data ;
93 ThreadId id = null;
94 if (len != 0) {
95 data = new byte[len];
96 readBytes(data);
97 id = new ThreadId(data);
99 int index = read16Bit();
100 if (index != 0xFFFF) {
101 if (len == 0) {
102 id = threadIdCache[index];
103 } else {
104 threadIdCache[index] = id;
107 return id;
108 } catch (IOException e) {
109 throw new RuntimeException(e);
113 public TypeDescription readType() {
114 int b = read8Bit();
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);
126 } else {
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];
135 if (type == null) {
136 throw new RuntimeException(
137 "Reading TYPE with empty cache index " + index);
139 } else {
140 try {
141 type = TypeDescription.getTypeDescription(
142 readStringValue());
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;
156 return type;
160 public Object readValue(TypeDescription type) {
161 try {
162 switch (type.getTypeClass().getValue()) {
163 case TypeClass.VOID_value:
164 return null;
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);
217 default:
218 throw new IllegalArgumentException("Bad type descriptor " + type);
220 } catch (IOException e) {
221 throw new RuntimeException(e);
225 public boolean hasMore() {
226 try {
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];
272 readBytes(data);
273 try {
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:
288 return Any.VOID;
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);
346 default:
347 return 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);
371 default:
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];
382 readBytes(data);
383 return data;
384 } else {
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));
391 return value;
395 private Enum readEnumValue(TypeDescription type) throws IOException {
396 try {
397 return (Enum)
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) {
411 Object value;
412 try {
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);
420 return value;
423 private Exception readExceptionValue(TypeDescription type) throws IOException {
424 Exception value;
425 try {
426 value = (Exception)
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);
439 return 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) {
458 try {
459 fields[i].getField().set(
460 value,
461 readValue(
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: */