xref: /AOO41X/main/jurt/com/sun/star/lib/uno/protocols/urp/Unmarshal.java (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 package com.sun.star.lib.uno.protocols.urp;
28 
29 import com.sun.star.lib.uno.environments.remote.ThreadId;
30 import com.sun.star.lib.uno.typedesc.TypeDescription;
31 import com.sun.star.uno.Any;
32 import com.sun.star.uno.Enum;
33 import com.sun.star.uno.IBridge;
34 import com.sun.star.uno.IFieldDescription;
35 import com.sun.star.uno.Type;
36 import com.sun.star.uno.TypeClass;
37 import com.sun.star.uno.XInterface;
38 import java.io.ByteArrayInputStream;
39 import java.io.DataInputStream;
40 import java.io.IOException;
41 import java.io.UnsupportedEncodingException;
42 import java.lang.reflect.Array;
43 import java.lang.reflect.InvocationTargetException;
44 
45 final class Unmarshal {
46     public Unmarshal(IBridge bridge, int cacheSize) {
47         this.bridge = bridge;
48         objectIdCache = new String[cacheSize];
49         threadIdCache = new ThreadId[cacheSize];
50         typeCache = new TypeDescription[cacheSize];
51         reset(new byte[0]);
52     }
53 
54     public int read8Bit() {
55         try {
56             return input.readUnsignedByte();
57         } catch (IOException e) {
58             throw new RuntimeException(e.toString());
59         }
60     }
61 
62     public int read16Bit() {
63         try {
64             return input.readUnsignedShort();
65         } catch (IOException e) {
66             throw new RuntimeException(e.toString());
67         }
68     }
69 
70     public String readObjectId() {
71         String id = readStringValue();
72         int index = read16Bit();
73         if (index == 0xFFFF) {
74             if (id.length() == 0) {
75                 id = null;
76             }
77         } else {
78             if (id.length() == 0) {
79                 id = objectIdCache[index];
80             } else {
81                 objectIdCache[index] = id;
82             }
83         }
84         return id;
85     }
86 
87     public Object readInterface(Type type) {
88         String id = readObjectId();
89         return id == null ? null : bridge.mapInterfaceFrom(id, type);
90     }
91 
92     public ThreadId readThreadId() {
93         int len = readCompressedNumber();
94         byte[] data  ;
95         ThreadId id = null;
96         if (len != 0) {
97             data = new byte[len];
98             readBytes(data);
99             id = new ThreadId(data);
100         }
101         int index = read16Bit();
102         if (index != 0xFFFF) {
103             if (len == 0) {
104                 id = threadIdCache[index];
105             } else {
106                 threadIdCache[index] = id;
107             }
108         }
109         return id;
110     }
111 
112     public TypeDescription readType() {
113         int b = read8Bit();
114         TypeClass typeClass = TypeClass.fromInt(b & 0x7F);
115         if (TypeDescription.isTypeClassSimple(typeClass)) {
116             return TypeDescription.getTypeDescription(typeClass);
117         } else {
118             int index = read16Bit();
119             TypeDescription type = null;
120             if ((b & 0x80) != 0) {
121                 try {
122                     type = TypeDescription.getTypeDescription(
123                         readStringValue());
124                 } catch (ClassNotFoundException e) {
125                     throw new RuntimeException(e.toString());
126                 }
127             }
128             if (index != 0xFFFF) {
129                 if ((b & 0x80) == 0) {
130                     type = typeCache[index];
131                 } else {
132                     typeCache[index] = type;
133                 }
134             }
135             return type;
136         }
137     }
138 
139     public Object readValue(TypeDescription type) {
140         switch (type.getTypeClass().getValue()) {
141         case TypeClass.VOID_value:
142             return null;
143 
144         case TypeClass.BOOLEAN_value:
145             return readBooleanValue();
146 
147         case TypeClass.BYTE_value:
148             return readByteValue();
149 
150         case TypeClass.SHORT_value:
151         case TypeClass.UNSIGNED_SHORT_value:
152             return readShortValue();
153 
154         case TypeClass.LONG_value:
155         case TypeClass.UNSIGNED_LONG_value:
156             return readLongValue();
157 
158         case TypeClass.HYPER_value:
159         case TypeClass.UNSIGNED_HYPER_value:
160             return readHyperValue();
161 
162         case TypeClass.FLOAT_value:
163             return readFloatValue();
164 
165         case TypeClass.DOUBLE_value:
166             return readDoubleValue();
167 
168         case TypeClass.CHAR_value:
169             return readCharValue();
170 
171         case TypeClass.STRING_value:
172             return readStringValue();
173 
174         case TypeClass.TYPE_value:
175             return readTypeValue();
176 
177         case TypeClass.ANY_value:
178             return readAnyValue();
179 
180         case TypeClass.SEQUENCE_value:
181             return readSequenceValue(type);
182 
183         case TypeClass.ENUM_value:
184             return readEnumValue(type);
185 
186         case TypeClass.STRUCT_value:
187             return readStructValue(type);
188 
189         case TypeClass.EXCEPTION_value:
190             return readExceptionValue(type);
191 
192         case TypeClass.INTERFACE_value:
193             return readInterfaceValue(type);
194 
195         default:
196             throw new IllegalArgumentException("Bad type descriptor " + type);
197         }
198     }
199 
200     public boolean hasMore() {
201         try {
202             return input.available() > 0;
203         } catch (IOException e) {
204             throw new RuntimeException(e.toString());
205         }
206     }
207 
208     public void reset(byte[] data) {
209         input = new DataInputStream(new ByteArrayInputStream(data));
210     }
211 
212     private Boolean readBooleanValue() {
213         try {
214             return input.readBoolean() ? Boolean.TRUE : Boolean.FALSE;
215         } catch (IOException e) {
216             throw new RuntimeException(e.toString());
217         }
218     }
219 
220     private Byte readByteValue() {
221         try {
222             return new Byte(input.readByte());
223         } catch (IOException e) {
224             throw new RuntimeException(e.toString());
225         }
226     }
227 
228     private Short readShortValue() {
229         try {
230             return new Short(input.readShort());
231         } catch (IOException e) {
232             throw new RuntimeException(e.toString());
233         }
234     }
235 
236     private Integer readLongValue() {
237         try {
238             return new Integer(input.readInt());
239         } catch (IOException e) {
240             throw new RuntimeException(e.toString());
241         }
242     }
243 
244     private Long readHyperValue() {
245         try {
246             return new Long(input.readLong());
247         } catch (IOException e) {
248             throw new RuntimeException(e.toString());
249         }
250     }
251 
252     private Float readFloatValue() {
253         try {
254             return new Float(input.readFloat());
255         } catch (IOException e) {
256             throw new RuntimeException(e.toString());
257         }
258     }
259 
260     private Double readDoubleValue() {
261         try {
262             return new Double(input.readDouble());
263         } catch (IOException e) {
264             throw new RuntimeException(e.toString());
265         }
266     }
267 
268     private Character readCharValue() {
269         try {
270             return new Character(input.readChar());
271         } catch (IOException e) {
272             throw new RuntimeException(e.toString());
273         }
274     }
275 
276     private String readStringValue() {
277         int len = readCompressedNumber();
278         byte[] data = new byte[len];
279         readBytes(data);
280         try {
281             return new String(data, "UTF8");
282         } catch (UnsupportedEncodingException e) {
283             throw new RuntimeException(e.toString());
284         }
285     }
286 
287     private Type readTypeValue() {
288         return new Type(readType());
289     }
290 
291     private Object readAnyValue() {
292         TypeDescription type = readType();
293         switch (type.getTypeClass().getValue()) {
294         case TypeClass.VOID_value:
295             return Any.VOID;
296 
297         case TypeClass.BOOLEAN_value:
298             return readBooleanValue();
299 
300         case TypeClass.BYTE_value:
301             return readByteValue();
302 
303         case TypeClass.SHORT_value:
304             return readShortValue();
305 
306         case TypeClass.UNSIGNED_SHORT_value:
307             return new Any(Type.UNSIGNED_SHORT, readShortValue());
308 
309         case TypeClass.LONG_value:
310             return readLongValue();
311 
312         case TypeClass.UNSIGNED_LONG_value:
313             return new Any(Type.UNSIGNED_LONG, readLongValue());
314 
315         case TypeClass.HYPER_value:
316             return readHyperValue();
317 
318         case TypeClass.UNSIGNED_HYPER_value:
319             return new Any(Type.UNSIGNED_HYPER, readHyperValue());
320 
321         case TypeClass.FLOAT_value:
322             return readFloatValue();
323 
324         case TypeClass.DOUBLE_value:
325             return readDoubleValue();
326 
327         case TypeClass.CHAR_value:
328             return readCharValue();
329 
330         case TypeClass.STRING_value:
331             return readStringValue();
332 
333         case TypeClass.TYPE_value:
334             return readTypeValue();
335 
336         case TypeClass.SEQUENCE_value:
337             {
338                 Object value = readSequenceValue(type);
339                 TypeDescription ctype = (TypeDescription)
340                     type.getComponentType();
341                 while (ctype.getTypeClass() == TypeClass.SEQUENCE) {
342                     ctype = (TypeDescription) ctype.getComponentType();
343                 }
344                 switch (ctype.getTypeClass().getValue()) {
345                 case TypeClass.UNSIGNED_SHORT_value:
346                 case TypeClass.UNSIGNED_LONG_value:
347                 case TypeClass.UNSIGNED_HYPER_value:
348                     return new Any(new Type(type), value);
349 
350                 case TypeClass.STRUCT_value:
351                     if (ctype.hasTypeArguments()) {
352                         return new Any(new Type(type), value);
353                     }
354                 default:
355                     return value;
356                 }
357             }
358 
359         case TypeClass.ENUM_value:
360             return readEnumValue(type);
361 
362         case TypeClass.STRUCT_value:
363             {
364                 Object value = readStructValue(type);
365                 return type.hasTypeArguments()
366                     ? new Any(new Type(type), value) : value;
367             }
368 
369         case TypeClass.EXCEPTION_value:
370             return readExceptionValue(type);
371 
372         case TypeClass.INTERFACE_value:
373             {
374                 Object value = readInterfaceValue(type);
375                 return type.getZClass() == XInterface.class
376                     ? value : new Any(new Type(type), value);
377             }
378 
379         default:
380             throw new RuntimeException(
381                 "Reading ANY with bad type " + type.getTypeClass());
382         }
383     }
384 
385     private Object readSequenceValue(TypeDescription type) {
386         int len = readCompressedNumber();
387         TypeDescription ctype = (TypeDescription) type.getComponentType();
388         if (ctype.getTypeClass() == TypeClass.BYTE) {
389             byte[] data = new byte[len];
390             readBytes(data);
391             return data;
392         } else {
393             Object value = Array.newInstance(
394                 ctype.getTypeClass() == TypeClass.ANY
395                 ? Object.class : ctype.getZClass(), len);
396             for (int i = 0; i < len; ++i) {
397                 Array.set(value, i, readValue(ctype));
398             }
399             return value;
400         }
401     }
402 
403     private Enum readEnumValue(TypeDescription type) {
404         try {
405             return (Enum)
406                 type.getZClass().getMethod(
407                     "fromInt", new Class[] { int.class }).
408                 invoke(null, new Object[] { readLongValue() });
409         } catch (IllegalAccessException e) {
410             throw new RuntimeException(e.toString());
411         } catch (InvocationTargetException e) {
412             throw new RuntimeException(e.toString());
413         } catch (NoSuchMethodException e) {
414             throw new RuntimeException(e.toString());
415         }
416     }
417 
418     private Object readStructValue(TypeDescription type) {
419         Object value;
420         try {
421             value = type.getZClass().newInstance();
422         } catch (IllegalAccessException e) {
423             throw new RuntimeException(e.toString());
424         } catch (InstantiationException e) {
425             throw new RuntimeException(e.toString());
426         }
427         readFields(type, value);
428         return value;
429     }
430 
431     private Exception readExceptionValue(TypeDescription type) {
432         Exception value;
433         try {
434             value = (Exception)
435                 type.getZClass().getConstructor(new Class[] { String.class }).
436                 newInstance(new Object[] { readStringValue() });
437         } catch (IllegalAccessException e) {
438             throw new RuntimeException(e.toString());
439         } catch (InstantiationException e) {
440             throw new RuntimeException(e.toString());
441         } catch (InvocationTargetException e) {
442             throw new RuntimeException(e.toString());
443         } catch (NoSuchMethodException e) {
444             throw new RuntimeException(e.toString());
445         }
446         readFields(type, value);
447         return value;
448     }
449 
450     private Object readInterfaceValue(TypeDescription type) {
451         return readInterface(new Type(type));
452     }
453 
454     private int readCompressedNumber() {
455         int number = read8Bit();
456         try {
457             return number < 0xFF ? number : input.readInt();
458         } catch (IOException e) {
459             throw new RuntimeException(e.toString());
460         }
461     }
462 
463     private void readBytes(byte[] data) {
464         try {
465             input.readFully(data);
466         } catch (IOException e) {
467             throw new RuntimeException(e.toString());
468         }
469     }
470 
471     private void readFields(TypeDescription type, Object value) {
472         IFieldDescription[] fields = type.getFieldDescriptions();
473         for (int i = 0; i < fields.length; ++i) {
474             try {
475                 fields[i].getField().set(
476                     value,
477                     readValue(
478                         (TypeDescription) fields[i].getTypeDescription()));
479             } catch (IllegalAccessException e) {
480                 throw new RuntimeException(e.toString());
481             }
482         }
483     }
484 
485     private final IBridge bridge;
486     private final String[] objectIdCache;
487     private final ThreadId[] threadIdCache;
488     private final TypeDescription[] typeCache;
489     private DataInputStream input;
490 }
491