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