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