1 /* 2 D-Bus Java Implementation 3 Copyright (c) 2005-2006 Matthew Johnson 4 5 This program is free software; you can redistribute it and/or modify it 6 under the terms of either the GNU Lesser General Public License Version 2 or the 7 Academic Free Licence Version 2.1. 8 9 Full licence texts are included in the COPYING file with this program. 10 */ 11 package org.freedesktop.dbus; 12 13 import static org.freedesktop.dbus.Gettext._; 14 15 import java.lang.reflect.Array; 16 import java.lang.reflect.Type; 17 import java.io.UnsupportedEncodingException; 18 import java.text.MessageFormat; 19 import java.util.Arrays; 20 import java.util.HashMap; 21 import java.util.List; 22 import java.util.Map; 23 import java.util.Vector; 24 25 import cx.ath.matthew.debug.Debug; 26 import cx.ath.matthew.utils.Hexdump; 27 28 import org.freedesktop.dbus.exceptions.DBusException; 29 import org.freedesktop.dbus.exceptions.MarshallingException; 30 import org.freedesktop.dbus.exceptions.UnknownTypeCodeException; 31 32 /** 33 * Superclass of all messages which are sent over the Bus. 34 * This class deals with all the marshalling to/from the wire format. 35 */ 36 public class Message 37 { 38 /** Defines constants representing the endianness of the message. */ 39 public static interface Endian { 40 public static final byte BIG = 'B'; 41 public static final byte LITTLE = 'l'; 42 } 43 /** Defines constants representing the flags which can be set on a message. */ 44 public static interface Flags { 45 public static final byte NO_REPLY_EXPECTED = 0x01; 46 public static final byte NO_AUTO_START = 0x02; 47 public static final byte ASYNC = 0x40; 48 } 49 /** Defines constants for each message type. */ 50 public static interface MessageType { 51 public static final byte METHOD_CALL = 1; 52 public static final byte METHOD_RETURN = 2; 53 public static final byte ERROR = 3; 54 public static final byte SIGNAL = 4; 55 } 56 /** The current protocol major version. */ 57 public static final byte PROTOCOL = 1; 58 /** Defines constants for each valid header field type. */ 59 public static interface HeaderField { 60 public static final byte PATH = 1; 61 public static final byte INTERFACE = 2; 62 public static final byte MEMBER = 3; 63 public static final byte ERROR_NAME = 4; 64 public static final byte REPLY_SERIAL = 5; 65 public static final byte DESTINATION = 6; 66 public static final byte SENDER = 7; 67 public static final byte SIGNATURE = 8; 68 } 69 /** Defines constants for each argument type. 70 * There are two constants for each argument type, 71 * as a byte or as a String (the _STRING version) */ 72 public static interface ArgumentType { 73 public static final String BYTE_STRING="y"; 74 public static final String BOOLEAN_STRING="b"; 75 public static final String INT16_STRING="n"; 76 public static final String UINT16_STRING="q"; 77 public static final String INT32_STRING="i"; 78 public static final String UINT32_STRING="u"; 79 public static final String INT64_STRING="x"; 80 public static final String UINT64_STRING="t"; 81 public static final String DOUBLE_STRING="d"; 82 public static final String FLOAT_STRING="f"; 83 public static final String STRING_STRING="s"; 84 public static final String OBJECT_PATH_STRING="o"; 85 public static final String SIGNATURE_STRING="g"; 86 public static final String ARRAY_STRING="a"; 87 public static final String VARIANT_STRING="v"; 88 public static final String STRUCT_STRING="r"; 89 public static final String STRUCT1_STRING="("; 90 public static final String STRUCT2_STRING=")"; 91 public static final String DICT_ENTRY_STRING="e"; 92 public static final String DICT_ENTRY1_STRING="{"; 93 public static final String DICT_ENTRY2_STRING="}"; 94 95 public static final byte BYTE='y'; 96 public static final byte BOOLEAN='b'; 97 public static final byte INT16='n'; 98 public static final byte UINT16='q'; 99 public static final byte INT32='i'; 100 public static final byte UINT32='u'; 101 public static final byte INT64='x'; 102 public static final byte UINT64='t'; 103 public static final byte DOUBLE='d'; 104 public static final byte FLOAT='f'; 105 public static final byte STRING='s'; 106 public static final byte OBJECT_PATH='o'; 107 public static final byte SIGNATURE='g'; 108 public static final byte ARRAY='a'; 109 public static final byte VARIANT='v'; 110 public static final byte STRUCT='r'; 111 public static final byte STRUCT1='('; 112 public static final byte STRUCT2=')'; 113 public static final byte DICT_ENTRY='e'; 114 public static final byte DICT_ENTRY1='{'; 115 public static final byte DICT_ENTRY2='}'; 116 } 117 /** Keep a static reference to each size of padding array to prevent allocation. */ 118 private static byte[][] padding; 119 static { 120 padding = new byte[][] { 121 null, 122 new byte[1], 123 new byte[2], 124 new byte[3], 125 new byte[4], 126 new byte[5], 127 new byte[6], 128 new byte[7] }; 129 } 130 /** Steps to increment the buffer array. */ 131 private static final int BUFFERINCREMENT = 20; 132 133 private boolean big; 134 protected byte[][] wiredata; 135 protected long bytecounter; 136 protected Map<Byte, Object> headers; 137 protected static long globalserial = 0; 138 protected long serial; 139 protected byte type; 140 protected byte flags; 141 protected byte protover; 142 private Object[] args; 143 private byte[] body; 144 private long bodylen = 0; 145 private int preallocated = 0; 146 private int paofs = 0; 147 private byte[] pabuf; 148 private int bufferuse = 0; 149 150 /** 151 * Returns the name of the given header field. 152 */ getHeaderFieldName(byte field)153 public static String getHeaderFieldName(byte field) 154 { 155 switch (field) { 156 case HeaderField.PATH: return "Path"; 157 case HeaderField.INTERFACE: return "Interface"; 158 case HeaderField.MEMBER: return "Member"; 159 case HeaderField.ERROR_NAME: return "Error Name"; 160 case HeaderField.REPLY_SERIAL: return "Reply Serial"; 161 case HeaderField.DESTINATION: return "Destination"; 162 case HeaderField.SENDER: return "Sender"; 163 case HeaderField.SIGNATURE: return "Signature"; 164 default: return "Invalid"; 165 } 166 } 167 168 /** 169 * Create a message; only to be called by sub-classes. 170 * @param endian The endianness to create the message. 171 * @param type The message type. 172 * @param flags Any message flags. 173 */ Message(byte endian, byte type, byte flags)174 protected Message(byte endian, byte type, byte flags) throws DBusException 175 { 176 wiredata = new byte[BUFFERINCREMENT][]; 177 headers = new HashMap<Byte, Object>(); 178 big = (Endian.BIG == endian); 179 bytecounter = 0; 180 synchronized (Message.class) { 181 serial = ++globalserial; 182 } 183 if (Debug.debug) Debug.print(Debug.DEBUG, "Creating message with serial "+serial); 184 this.type = type; 185 this.flags = flags; 186 preallocate(4); 187 append("yyyy", endian, type, flags, Message.PROTOCOL); 188 } 189 /** 190 * Create a blank message. Only to be used when calling populate. 191 */ Message()192 protected Message() 193 { 194 wiredata = new byte[BUFFERINCREMENT][]; 195 headers = new HashMap<Byte, Object>(); 196 bytecounter = 0; 197 } 198 /** 199 * Create a message from wire-format data. 200 * @param msg D-Bus serialized data of type yyyuu 201 * @param headers D-Bus serialized data of type a(yv) 202 * @param body D-Bus serialized data of the signature defined in headers. 203 */ 204 @SuppressWarnings("unchecked") populate(byte[] msg, byte[] headers, byte[] body)205 void populate(byte[] msg, byte[] headers, byte[] body) throws DBusException 206 { 207 big = (msg[0] == Endian.BIG); 208 type = msg[1]; 209 flags = msg[2]; 210 protover = msg[3]; 211 wiredata[0] = msg; 212 wiredata[1] = headers; 213 wiredata[2] = body; 214 this.body = body; 215 bufferuse = 3; 216 bodylen = ((Number) extract(Message.ArgumentType.UINT32_STRING, msg, 4)[0]).longValue(); 217 serial = ((Number) extract(Message.ArgumentType.UINT32_STRING, msg, 8)[0]).longValue(); 218 bytecounter = msg.length+headers.length+body.length; 219 if (Debug.debug) Debug.print(Debug.VERBOSE, headers); 220 Object[] hs = extract("a(yv)", headers, 0); 221 if (Debug.debug) Debug.print(Debug.VERBOSE, Arrays.deepToString(hs)); 222 for (Object o: (Vector<Object>) hs[0]) { 223 this.headers.put((Byte) ((Object[])o)[0], ((Variant<Object>)((Object[])o)[1]).getValue()); 224 } 225 } 226 /** 227 * Create a buffer of num bytes. 228 * Data is copied to this rather than added to the buffer list. 229 */ preallocate(int num)230 private void preallocate(int num) 231 { 232 preallocated = 0; 233 pabuf = new byte[num]; 234 appendBytes(pabuf); 235 preallocated = num; 236 paofs = 0; 237 } 238 /** 239 * Ensures there are enough free buffers. 240 * @param num number of free buffers to create. 241 */ ensureBuffers(int num)242 private void ensureBuffers(int num) 243 { 244 int increase = num - wiredata.length + bufferuse; 245 if (increase > 0) { 246 if (increase < BUFFERINCREMENT) increase = BUFFERINCREMENT; 247 if (Debug.debug) Debug.print(Debug.VERBOSE, "Resizing "+bufferuse); 248 byte[][] temp = new byte[wiredata.length+increase][]; 249 System.arraycopy(wiredata, 0, temp, 0, wiredata.length); 250 wiredata = temp; 251 } 252 } 253 /** 254 * Appends a buffer to the buffer list. 255 */ appendBytes(byte[] buf)256 protected void appendBytes(byte[] buf) 257 { 258 if (null == buf) return; 259 if (preallocated > 0) { 260 if (paofs+buf.length > pabuf.length) 261 throw new ArrayIndexOutOfBoundsException(MessageFormat.format(_("Array index out of bounds, paofs={0}, pabuf.length={1}, buf.length={2}."), new Object[] { paofs, pabuf.length, buf.length })); 262 System.arraycopy(buf, 0, pabuf, paofs, buf.length); 263 paofs += buf.length; 264 preallocated -= buf.length; 265 } else { 266 if (bufferuse == wiredata.length) { 267 if (Debug.debug) Debug.print(Debug.VERBOSE, "Resizing "+bufferuse); 268 byte[][] temp = new byte[wiredata.length+BUFFERINCREMENT][]; 269 System.arraycopy(wiredata, 0, temp, 0, wiredata.length); 270 wiredata = temp; 271 } 272 wiredata[bufferuse++] = buf; 273 bytecounter += buf.length; 274 } 275 } 276 /** 277 * Appends a byte to the buffer list. 278 */ appendByte(byte b)279 protected void appendByte(byte b) 280 { 281 if (preallocated > 0) { 282 pabuf[paofs++] = b; 283 preallocated--; 284 } else { 285 if (bufferuse == wiredata.length) { 286 if (Debug.debug) Debug.print(Debug.VERBOSE, "Resizing "+bufferuse); 287 byte[][] temp = new byte[wiredata.length+BUFFERINCREMENT][]; 288 System.arraycopy(wiredata, 0, temp, 0, wiredata.length); 289 wiredata = temp; 290 } 291 wiredata[bufferuse++] = new byte[] { b }; 292 bytecounter++; 293 } 294 } 295 /** 296 * Demarshalls an integer of a given width from a buffer. 297 * Endianness is determined from the format of the message. 298 * @param buf The buffer to demarshall from. 299 * @param ofs The offset to demarshall from. 300 * @param width The byte-width of the int. 301 */ demarshallint(byte[] buf, int ofs, int width)302 public long demarshallint(byte[] buf, int ofs, int width) 303 { return big ? demarshallintBig(buf,ofs,width) : demarshallintLittle(buf,ofs,width); } 304 /** 305 * Demarshalls an integer of a given width from a buffer. 306 * @param buf The buffer to demarshall from. 307 * @param ofs The offset to demarshall from. 308 * @param endian The endianness to use in demarshalling. 309 * @param width The byte-width of the int. 310 */ demarshallint(byte[] buf, int ofs, byte endian, int width)311 public static long demarshallint(byte[] buf, int ofs, byte endian, int width) 312 { return endian==Endian.BIG ? demarshallintBig(buf,ofs,width) : demarshallintLittle(buf,ofs,width); } 313 /** 314 * Demarshalls an integer of a given width from a buffer using big-endian format. 315 * @param buf The buffer to demarshall from. 316 * @param ofs The offset to demarshall from. 317 * @param width The byte-width of the int. 318 */ demarshallintBig(byte[] buf, int ofs, int width)319 public static long demarshallintBig(byte[] buf, int ofs, int width) 320 { 321 long l = 0; 322 for (int i = 0; i < width; i++) { 323 l <<=8; 324 l |= (buf[ofs+i] & 0xFF); 325 } 326 return l; 327 } 328 /** 329 * Demarshalls an integer of a given width from a buffer using little-endian format. 330 * @param buf The buffer to demarshall from. 331 * @param ofs The offset to demarshall from. 332 * @param width The byte-width of the int. 333 */ demarshallintLittle(byte[] buf, int ofs, int width)334 public static long demarshallintLittle(byte[] buf, int ofs, int width) 335 { 336 long l = 0; 337 for (int i = (width-1); i >= 0; i--) { 338 l <<=8; 339 l |= (buf[ofs+i] & 0xFF); 340 } 341 return l; 342 } 343 /** 344 * Marshalls an integer of a given width and appends it to the message. 345 * Endianness is determined from the message. 346 * @param l The integer to marshall. 347 * @param width The byte-width of the int. 348 */ appendint(long l, int width)349 public void appendint(long l, int width) 350 { 351 byte[] buf = new byte[width]; 352 marshallint(l, buf, 0, width); 353 appendBytes(buf); 354 } 355 /** 356 * Marshalls an integer of a given width into a buffer. 357 * Endianness is determined from the message. 358 * @param l The integer to marshall. 359 * @param buf The buffer to marshall to. 360 * @param ofs The offset to marshall to. 361 * @param width The byte-width of the int. 362 */ marshallint(long l, byte[] buf, int ofs, int width)363 public void marshallint(long l, byte[] buf, int ofs, int width) 364 { 365 if (big) marshallintBig(l, buf, ofs, width); else marshallintLittle(l, buf, ofs, width); 366 if (Debug.debug) Debug.print(Debug.VERBOSE, "Marshalled int "+l+" to "+Hexdump.toHex(buf,ofs,width)); 367 } 368 /** 369 * Marshalls an integer of a given width into a buffer using big-endian format. 370 * @param l The integer to marshall. 371 * @param buf The buffer to marshall to. 372 * @param ofs The offset to marshall to. 373 * @param width The byte-width of the int. 374 */ marshallintBig(long l, byte[] buf, int ofs, int width)375 public static void marshallintBig(long l, byte[] buf, int ofs, int width) 376 { 377 for (int i = (width-1); i >= 0; i--) { 378 buf[i+ofs] = (byte) (l & 0xFF); 379 l >>= 8; 380 } 381 } 382 /** 383 * Marshalls an integer of a given width into a buffer using little-endian format. 384 * @param l The integer to marshall. 385 * @param buf The buffer to demarshall to. 386 * @param ofs The offset to demarshall to. 387 * @param width The byte-width of the int. 388 */ marshallintLittle(long l, byte[] buf, int ofs, int width)389 public static void marshallintLittle(long l, byte[] buf, int ofs, int width) 390 { 391 for (int i = 0; i < width; i++) { 392 buf[i+ofs] = (byte) (l & 0xFF); 393 l >>= 8; 394 } 395 } getWireData()396 public byte[][] getWireData() 397 { 398 return wiredata; 399 } 400 /** 401 * Formats the message in a human-readable format. 402 */ toString()403 public String toString() 404 { 405 StringBuffer sb = new StringBuffer(); 406 sb.append(getClass().getSimpleName()); 407 sb.append ('('); 408 sb.append (flags); 409 sb.append (','); 410 sb.append(serial); 411 sb.append (')'); 412 sb.append (' '); 413 sb.append ('{'); 414 sb.append(' '); 415 if (headers.size() == 0) 416 sb.append('}'); 417 else { 418 for (Byte field: headers.keySet()) { 419 sb.append(getHeaderFieldName(field)); 420 sb.append('='); 421 sb.append('>'); 422 sb.append(headers.get(field).toString()); 423 sb.append(','); 424 sb.append(' '); 425 } 426 sb.setCharAt(sb.length()-2,' '); 427 sb.setCharAt(sb.length()-1,'}'); 428 } 429 sb.append(' '); 430 sb.append('{'); 431 sb.append(' '); 432 Object[] args = null; 433 try { 434 args = getParameters(); 435 } catch (DBusException DBe) { 436 if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBe); 437 } 438 if (null == args || 0 == args.length) 439 sb.append('}'); 440 else { 441 for (Object o: args) { 442 if (o instanceof Object[]) 443 sb.append(Arrays.deepToString((Object[]) o)); 444 else if (o instanceof byte[]) 445 sb.append(Arrays.toString((byte[]) o)); 446 else if (o instanceof int[]) 447 sb.append(Arrays.toString((int[]) o)); 448 else if (o instanceof short[]) 449 sb.append(Arrays.toString((short[]) o)); 450 else if (o instanceof long[]) 451 sb.append(Arrays.toString((long[]) o)); 452 else if (o instanceof boolean[]) 453 sb.append(Arrays.toString((boolean[]) o)); 454 else if (o instanceof double[]) 455 sb.append(Arrays.toString((double[]) o)); 456 else if (o instanceof float[]) 457 sb.append(Arrays.toString((float[]) o)); 458 else 459 sb.append(o.toString()); 460 sb.append(','); 461 sb.append(' '); 462 } 463 sb.setCharAt(sb.length()-2,' '); 464 sb.setCharAt(sb.length()-1,'}'); 465 } 466 return sb.toString(); 467 } 468 /** 469 * Returns the value of the header field of a given field. 470 * @param type The field to return. 471 * @return The value of the field or null if unset. 472 */ getHeader(byte type)473 public Object getHeader(byte type) { return headers.get(type); } 474 /** 475 * Appends a value to the message. 476 * The type of the value is read from a D-Bus signature and used to marshall 477 * the value. 478 * @param sigb A buffer of the D-Bus signature. 479 * @param sigofs The offset into the signature corresponding to this value. 480 * @param data The value to marshall. 481 * @return The offset into the signature of the end of this value's type. 482 */ 483 @SuppressWarnings("unchecked") appendone(byte[] sigb, int sigofs, Object data)484 private int appendone(byte[] sigb, int sigofs, Object data) throws DBusException 485 { 486 try { 487 int i = sigofs; 488 if (Debug.debug) Debug.print(Debug.VERBOSE, (Object) bytecounter); 489 if (Debug.debug) Debug.print(Debug.VERBOSE, "Appending type: "+((char)sigb[i])+" value: "+data); 490 491 // pad to the alignment of this type. 492 pad(sigb[i]); 493 switch (sigb[i]) { 494 case ArgumentType.BYTE: 495 appendByte(((Number) data).byteValue()); 496 break; 497 case ArgumentType.BOOLEAN: 498 appendint(((Boolean) data).booleanValue() ? 1 : 0, 4); 499 break; 500 case ArgumentType.DOUBLE: 501 long l = Double.doubleToLongBits(((Number) data).doubleValue()); 502 appendint(l, 8); 503 break; 504 case ArgumentType.FLOAT: 505 int rf = Float.floatToIntBits(((Number) data).floatValue()); 506 appendint(rf, 4); 507 break; 508 case ArgumentType.UINT32: 509 appendint(((Number) data).longValue(), 4); 510 break; 511 case ArgumentType.INT64: 512 appendint(((Number) data).longValue(), 8); 513 break; 514 case ArgumentType.UINT64: 515 if (big) { 516 appendint(((UInt64) data).top(), 4); 517 appendint(((UInt64) data).bottom(), 4); 518 } else { 519 appendint(((UInt64) data).bottom(), 4); 520 appendint(((UInt64) data).top(), 4); 521 } 522 break; 523 case ArgumentType.INT32: 524 appendint(((Number) data).intValue(), 4); 525 break; 526 case ArgumentType.UINT16: 527 appendint(((Number) data).intValue(), 2); 528 break; 529 case ArgumentType.INT16: 530 appendint(((Number) data).shortValue(), 2); 531 break; 532 case ArgumentType.STRING: 533 case ArgumentType.OBJECT_PATH: 534 // Strings are marshalled as a UInt32 with the length, 535 // followed by the String, followed by a null byte. 536 String payload = data.toString(); 537 byte[] payloadbytes = null; 538 try { 539 payloadbytes = payload.getBytes("UTF-8"); 540 } catch (UnsupportedEncodingException UEe) { 541 if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(UEe); 542 throw new DBusException(_("System does not support UTF-8 encoding")); 543 } 544 if (Debug.debug) Debug.print(Debug.VERBOSE, "Appending String of length "+payloadbytes.length); 545 appendint(payloadbytes.length, 4); 546 appendBytes(payloadbytes); 547 appendBytes(padding[1]); 548 //pad(ArgumentType.STRING);? do we need this? 549 break; 550 case ArgumentType.SIGNATURE: 551 // Signatures are marshalled as a byte with the length, 552 // followed by the String, followed by a null byte. 553 // Signatures are generally short, so preallocate the array 554 // for the string, length and null byte. 555 if (data instanceof Type[]) 556 payload = Marshalling.getDBusType((Type[]) data); 557 else 558 payload = (String) data; 559 byte[] pbytes = payload.getBytes(); 560 preallocate(2+pbytes.length); 561 appendByte((byte) pbytes.length); 562 appendBytes(pbytes); 563 appendByte((byte) 0); 564 break; 565 case ArgumentType.ARRAY: 566 // Arrays are given as a UInt32 for the length in bytes, 567 // padding to the element alignment, then elements in 568 // order. The length is the length from the end of the 569 // initial padding to the end of the last element. 570 if (Debug.debug) { 571 if (data instanceof Object[]) 572 Debug.print(Debug.VERBOSE, "Appending array: "+Arrays.deepToString((Object[])data)); 573 } 574 575 byte[] alen = new byte[4]; 576 appendBytes(alen); 577 pad(sigb[++i]); 578 long c = bytecounter; 579 580 // optimise primatives 581 if (data.getClass().isArray() && 582 data.getClass().getComponentType().isPrimitive()) { 583 byte[] primbuf; 584 int algn = getAlignment(sigb[i]); 585 int len = Array.getLength(data); 586 switch (sigb[i]) { 587 case ArgumentType.BYTE: 588 primbuf = (byte[]) data; 589 break; 590 case ArgumentType.INT16: 591 case ArgumentType.INT32: 592 case ArgumentType.INT64: 593 primbuf = new byte[len*algn]; 594 for (int j = 0, k = 0; j < len; j++, k += algn) 595 marshallint(Array.getLong(data, j), primbuf, k, algn); 596 break; 597 case ArgumentType.BOOLEAN: 598 primbuf = new byte[len*algn]; 599 for (int j = 0, k = 0; j < len; j++, k += algn) 600 marshallint(Array.getBoolean(data, j)?1:0, primbuf, k, algn); 601 break; 602 case ArgumentType.DOUBLE: 603 primbuf = new byte[len*algn]; 604 if (data instanceof float[]) 605 for (int j = 0, k = 0; j < len; j++, k += algn) 606 marshallint(Double.doubleToRawLongBits(((float[])data)[j]), 607 primbuf, k, algn); 608 else 609 for (int j = 0, k = 0; j < len; j++, k += algn) 610 marshallint(Double.doubleToRawLongBits(((double[])data)[j]), 611 primbuf, k, algn); 612 break; 613 case ArgumentType.FLOAT: 614 primbuf = new byte[len*algn]; 615 for (int j = 0, k = 0; j < len; j++, k += algn) 616 marshallint( 617 Float.floatToRawIntBits(((float[])data)[j]), 618 primbuf, k, algn); 619 break; 620 default: 621 throw new MarshallingException(_("Primative array being sent as non-primative array.")); 622 } 623 appendBytes(primbuf); 624 } else if (data instanceof List) { 625 Object[] contents = ((List) data).toArray(); 626 int diff = i; 627 ensureBuffers(contents.length*4); 628 for (Object o: contents) 629 diff = appendone(sigb, i, o); 630 i = diff; 631 } else if (data instanceof Map) { 632 int diff = i; 633 ensureBuffers(((Map) data).size()*6); 634 for (Map.Entry<Object,Object> o: ((Map<Object,Object>) data).entrySet()) 635 diff = appendone(sigb, i, o); 636 if (i == diff) { 637 // advance the type parser even on 0-size arrays. 638 Vector<Type> temp = new Vector<Type>(); 639 byte[] temp2 = new byte[sigb.length-diff]; 640 System.arraycopy(sigb, diff, temp2, 0, temp2.length); 641 String temp3 = new String(temp2); 642 int temp4 = Marshalling.getJavaType(temp3, temp, 1); 643 diff += temp4; 644 } 645 i = diff; 646 } else { 647 Object[] contents = (Object[]) data; 648 ensureBuffers(contents.length*4); 649 int diff = i; 650 for (Object o: contents) 651 diff = appendone(sigb, i, o); 652 i = diff; 653 } 654 if (Debug.debug) Debug.print(Debug.VERBOSE, "start: "+c+" end: "+bytecounter+" length: "+(bytecounter-c)); 655 marshallint(bytecounter-c, alen, 0, 4); 656 break; 657 case ArgumentType.STRUCT1: 658 // Structs are aligned to 8 bytes 659 // and simply contain each element marshalled in order 660 Object[] contents; 661 if (data instanceof Container) 662 contents = ((Container) data).getParameters(); 663 else 664 contents = (Object[]) data; 665 ensureBuffers(contents.length*4); 666 int j = 0; 667 for (i++; sigb[i] != ArgumentType.STRUCT2; i++) 668 i = appendone(sigb, i, contents[j++]); 669 break; 670 case ArgumentType.DICT_ENTRY1: 671 // Dict entries are the same as structs. 672 if (data instanceof Map.Entry) { 673 i++; 674 i = appendone(sigb, i, ((Map.Entry) data).getKey()); 675 i++; 676 i = appendone(sigb, i, ((Map.Entry) data).getValue()); 677 i++; 678 } else { 679 contents = (Object[]) data; 680 j = 0; 681 for (i++; sigb[i] != ArgumentType.DICT_ENTRY2; i++) 682 i = appendone(sigb, i, contents[j++]); 683 } 684 break; 685 case ArgumentType.VARIANT: 686 // Variants are marshalled as a signature 687 // followed by the value. 688 if (data instanceof Variant) { 689 Variant var = (Variant) data; 690 appendone(new byte[] {ArgumentType.SIGNATURE}, 0, var.getSig()); 691 appendone((var.getSig()).getBytes(), 0, var.getValue()); 692 } else if (data instanceof Object[]) { 693 contents = (Object[]) data; 694 appendone(new byte[] {ArgumentType.SIGNATURE}, 0, contents[0]); 695 appendone(((String) contents[0]).getBytes(), 0, contents[1]); 696 } else { 697 String sig = Marshalling.getDBusType(data.getClass())[0]; 698 appendone(new byte[] {ArgumentType.SIGNATURE}, 0, sig); 699 appendone((sig).getBytes(), 0, data); 700 } 701 break; 702 } 703 return i; 704 } catch (ClassCastException CCe) { 705 if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, CCe); 706 throw new MarshallingException(MessageFormat.format(_("Trying to marshall to unconvertable type (from {0} to {1})."), new Object[] { data.getClass().getName(), sigb[sigofs] })); 707 } 708 } 709 /** 710 * Pad the message to the proper alignment for the given type. 711 */ pad(byte type)712 public void pad(byte type) 713 { 714 if (Debug.debug) Debug.print(Debug.VERBOSE, "padding for "+(char)type); 715 int a = getAlignment(type); 716 if (Debug.debug) Debug.print(Debug.VERBOSE, preallocated+" "+paofs+" "+bytecounter+" "+a); 717 int b = (int) ((bytecounter-preallocated)%a); 718 if (0 == b) return; 719 a = (a-b); 720 if (preallocated > 0) { 721 paofs += a; 722 preallocated -= a; 723 } else 724 appendBytes(padding[a]); 725 if (Debug.debug) Debug.print(Debug.VERBOSE, preallocated+" "+paofs+" "+bytecounter+" "+a); 726 } 727 /** 728 * Return the alignment for a given type. 729 */ getAlignment(byte type)730 public static int getAlignment(byte type) 731 { 732 switch (type) { 733 case 2: 734 case ArgumentType.INT16: 735 case ArgumentType.UINT16: 736 return 2; 737 case 4: 738 case ArgumentType.BOOLEAN: 739 case ArgumentType.FLOAT: 740 case ArgumentType.INT32: 741 case ArgumentType.UINT32: 742 case ArgumentType.STRING: 743 case ArgumentType.OBJECT_PATH: 744 case ArgumentType.ARRAY: 745 return 4; 746 case 8: 747 case ArgumentType.INT64: 748 case ArgumentType.UINT64: 749 case ArgumentType.DOUBLE: 750 case ArgumentType.STRUCT: 751 case ArgumentType.DICT_ENTRY: 752 case ArgumentType.STRUCT1: 753 case ArgumentType.DICT_ENTRY1: 754 case ArgumentType.STRUCT2: 755 case ArgumentType.DICT_ENTRY2: 756 return 8; 757 case 1: 758 case ArgumentType.BYTE: 759 case ArgumentType.SIGNATURE: 760 case ArgumentType.VARIANT: 761 default: 762 return 1; 763 } 764 } 765 /** 766 * Append a series of values to the message. 767 * @param sig The signature(s) of the value(s). 768 * @param data The value(s). 769 */ append(String sig, Object... data)770 public void append(String sig, Object... data) throws DBusException 771 { 772 if (Debug.debug) Debug.print(Debug.DEBUG, "Appending sig: "+sig+" data: "+Arrays.deepToString(data)); 773 byte[] sigb = sig.getBytes(); 774 int j = 0; 775 for (int i = 0; i < sigb.length; i++) { 776 if (Debug.debug) Debug.print(Debug.VERBOSE, "Appending item: "+i+" "+((char)sigb[i])+" "+j); 777 i = appendone(sigb, i, data[j++]); 778 } 779 } 780 /** 781 * Align a counter to the given type. 782 * @param current The current counter. 783 * @param type The type to align to. 784 * @return The new, aligned, counter. 785 */ align(int current, byte type)786 public int align(int current, byte type) 787 { 788 if (Debug.debug) Debug.print(Debug.VERBOSE, "aligning to "+(char)type); 789 int a = getAlignment(type); 790 if (0 == (current%a)) return current; 791 return current+(a-(current%a)); 792 } 793 /** 794 * Demarshall one value from a buffer. 795 * @param sigb A buffer of the D-Bus signature. 796 * @param buf The buffer to demarshall from. 797 * @param ofs An array of two ints, the offset into the signature buffer 798 * and the offset into the data buffer. These values will be 799 * updated to the start of the next value ofter demarshalling. 800 * @param contained converts nested arrays to Lists 801 * @return The demarshalled value. 802 */ extractone(byte[] sigb, byte[] buf, int[] ofs, boolean contained)803 private Object extractone(byte[] sigb, byte[] buf, int[] ofs, boolean contained) throws DBusException 804 { 805 if (Debug.debug) Debug.print(Debug.VERBOSE, "Extracting type: "+((char)sigb[ofs[0]])+" from offset "+ofs[1]); 806 Object rv = null; 807 ofs[1] = align(ofs[1], sigb[ofs[0]]); 808 switch (sigb[ofs[0]]) { 809 case ArgumentType.BYTE: 810 rv = buf[ofs[1]++]; 811 break; 812 case ArgumentType.UINT32: 813 rv = new UInt32(demarshallint(buf, ofs[1], 4)); 814 ofs[1] += 4; 815 break; 816 case ArgumentType.INT32: 817 rv = (int) demarshallint(buf, ofs[1], 4); 818 ofs[1] += 4; 819 break; 820 case ArgumentType.INT16: 821 rv = (short) demarshallint(buf, ofs[1], 2); 822 ofs[1] += 2; 823 break; 824 case ArgumentType.UINT16: 825 rv = new UInt16((int) demarshallint(buf, ofs[1], 2)); 826 ofs[1] += 2; 827 break; 828 case ArgumentType.INT64: 829 rv = demarshallint(buf, ofs[1], 8); 830 ofs[1] += 8; 831 break; 832 case ArgumentType.UINT64: 833 long top; 834 long bottom; 835 if (big) { 836 top = demarshallint(buf, ofs[1], 4); 837 ofs[1] += 4; 838 bottom = demarshallint(buf, ofs[1], 4); 839 } else { 840 bottom = demarshallint(buf, ofs[1], 4); 841 ofs[1] += 4; 842 top = demarshallint(buf, ofs[1], 4); 843 } 844 rv = new UInt64(top, bottom); 845 ofs[1] += 4; 846 break; 847 case ArgumentType.DOUBLE: 848 long l = demarshallint(buf, ofs[1], 8); 849 ofs[1] += 8; 850 rv = Double.longBitsToDouble(l); 851 break; 852 case ArgumentType.FLOAT: 853 int rf = (int) demarshallint(buf, ofs[1], 4); 854 ofs[1] += 4; 855 rv = Float.intBitsToFloat(rf); 856 break; 857 case ArgumentType.BOOLEAN: 858 rf = (int) demarshallint(buf, ofs[1], 4); 859 ofs[1] += 4; 860 rv = (1==rf)?Boolean.TRUE:Boolean.FALSE; 861 break; 862 case ArgumentType.ARRAY: 863 long size = demarshallint(buf, ofs[1], 4); 864 if (Debug.debug) Debug.print(Debug.VERBOSE, "Reading array of size: "+size); 865 ofs[1] += 4; 866 byte algn = (byte) getAlignment(sigb[++ofs[0]]); 867 ofs[1] = align(ofs[1], sigb[ofs[0]]); 868 int length = (int) (size / algn); 869 if (length > DBusConnection.MAX_ARRAY_LENGTH) 870 throw new MarshallingException(_("Arrays must not exceed ")+DBusConnection.MAX_ARRAY_LENGTH); 871 // optimise primatives 872 switch (sigb[ofs[0]]) { 873 case ArgumentType.BYTE: 874 rv = new byte[length]; 875 System.arraycopy(buf, ofs[1], rv, 0, length); 876 ofs[1] += size; 877 break; 878 case ArgumentType.INT16: 879 rv = new short[length]; 880 for (int j = 0; j < length; j++, ofs[1] += algn) 881 ((short[]) rv)[j] = (short) demarshallint(buf, ofs[1], algn); 882 break; 883 case ArgumentType.INT32: 884 rv = new int[length]; 885 for (int j = 0; j < length; j++, ofs[1] += algn) 886 ((int[]) rv)[j] = (int) demarshallint(buf, ofs[1], algn); 887 break; 888 case ArgumentType.INT64: 889 rv = new long[length]; 890 for (int j = 0; j < length; j++, ofs[1] += algn) 891 ((long[]) rv)[j] = demarshallint(buf, ofs[1], algn); 892 break; 893 case ArgumentType.BOOLEAN: 894 rv = new boolean[length]; 895 for (int j = 0; j < length; j++, ofs[1] += algn) 896 ((boolean[]) rv)[j] = (1 == demarshallint(buf, ofs[1], algn)); 897 break; 898 case ArgumentType.FLOAT: 899 rv = new float[length]; 900 for (int j = 0; j < length; j++, ofs[1] += algn) 901 ((float[]) rv)[j] = 902 Float.intBitsToFloat((int)demarshallint(buf, ofs[1], algn)); 903 break; 904 case ArgumentType.DOUBLE: 905 rv = new double[length]; 906 for (int j = 0; j < length; j++, ofs[1] += algn) 907 ((double[]) rv)[j] = 908 Double.longBitsToDouble(demarshallint(buf, ofs[1], algn)); 909 break; 910 case ArgumentType.DICT_ENTRY1: 911 if (0 == size) { 912 // advance the type parser even on 0-size arrays. 913 Vector<Type> temp = new Vector<Type>(); 914 byte[] temp2 = new byte[sigb.length-ofs[0]]; 915 System.arraycopy(sigb, ofs[0], temp2, 0, temp2.length); 916 String temp3 = new String(temp2); 917 // ofs[0] gets incremented anyway. Leave one character on the stack 918 int temp4 = Marshalling.getJavaType(temp3, temp, 1) - 1; 919 ofs[0] += temp4; 920 if (Debug.debug) Debug.print(Debug.VERBOSE, "Aligned type: "+temp3+" "+temp4+" "+ofs[0]); 921 } 922 int ofssave = ofs[0]; 923 long end = ofs[1]+size; 924 Vector<Object[]> entries = new Vector<Object[]>(); 925 while (ofs[1] < end) { 926 ofs[0] = ofssave; 927 entries.add((Object[]) extractone(sigb, buf, ofs, true)); 928 } 929 rv = new DBusMap<Object, Object>(entries.toArray(new Object[0][])); 930 break; 931 default: 932 if (0 == size) { 933 // advance the type parser even on 0-size arrays. 934 Vector<Type> temp = new Vector<Type>(); 935 byte[] temp2 = new byte[sigb.length-ofs[0]]; 936 System.arraycopy(sigb, ofs[0], temp2, 0, temp2.length); 937 String temp3 = new String(temp2); 938 // ofs[0] gets incremented anyway. Leave one character on the stack 939 int temp4 = Marshalling.getJavaType(temp3, temp, 1) - 1; 940 ofs[0] += temp4; 941 if (Debug.debug) Debug.print(Debug.VERBOSE, "Aligned type: "+temp3+" "+temp4+" "+ofs[0]); 942 } 943 ofssave = ofs[0]; 944 end = ofs[1]+size; 945 Vector<Object> contents = new Vector<Object>(); 946 while (ofs[1] < end) { 947 ofs[0] = ofssave; 948 contents.add(extractone(sigb, buf, ofs, true)); 949 } 950 rv = contents; 951 } 952 if (contained && !(rv instanceof List) && !(rv instanceof Map)) 953 rv = ArrayFrob.listify(rv); 954 break; 955 case ArgumentType.STRUCT1: 956 Vector<Object> contents = new Vector<Object>(); 957 while (sigb[++ofs[0]] != ArgumentType.STRUCT2) 958 contents.add(extractone(sigb, buf, ofs, true)); 959 rv = contents.toArray(); 960 break; 961 case ArgumentType.DICT_ENTRY1: 962 Object[] decontents = new Object[2]; 963 if (Debug.debug) Debug.print(Debug.VERBOSE, "Extracting Dict Entry ("+Hexdump.toAscii(sigb,ofs[0],sigb.length-ofs[0])+") from: "+Hexdump.toHex(buf,ofs[1],buf.length-ofs[1])); 964 ofs[0]++; 965 decontents[0] = extractone(sigb, buf, ofs, true); 966 ofs[0]++; 967 decontents[1] = extractone(sigb, buf, ofs, true); 968 ofs[0]++; 969 rv = decontents; 970 break; 971 case ArgumentType.VARIANT: 972 int[] newofs = new int[] { 0, ofs[1] }; 973 String sig = (String) extract(ArgumentType.SIGNATURE_STRING, buf, newofs)[0]; 974 newofs[0] = 0; 975 rv = new Variant<Object>(extract(sig, buf, newofs)[0] , sig); 976 ofs[1] = newofs[1]; 977 break; 978 case ArgumentType.STRING: 979 length = (int) demarshallint(buf, ofs[1], 4); 980 ofs[1] += 4; 981 try { 982 rv = new String(buf, ofs[1], length, "UTF-8"); 983 } catch (UnsupportedEncodingException UEe) { 984 if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(UEe); 985 throw new DBusException(_("System does not support UTF-8 encoding")); 986 } 987 ofs[1] += length + 1; 988 break; 989 case ArgumentType.OBJECT_PATH: 990 length = (int) demarshallint(buf, ofs[1], 4); 991 ofs[1] += 4; 992 rv = new ObjectPath(getSource(), new String(buf, ofs[1], length)); 993 ofs[1] += length + 1; 994 break; 995 case ArgumentType.SIGNATURE: 996 length = (buf[ofs[1]++] & 0xFF); 997 rv = new String(buf, ofs[1], length); 998 ofs[1] += length + 1; 999 break; 1000 default: 1001 throw new UnknownTypeCodeException(sigb[ofs[0]]); 1002 } 1003 if (Debug.debug) if (rv instanceof Object[]) 1004 Debug.print(Debug.VERBOSE, "Extracted: "+Arrays.deepToString((Object[]) rv)+" (now at "+ofs[1]+")"); 1005 else 1006 Debug.print(Debug.VERBOSE, "Extracted: "+rv+" (now at "+ofs[1]+")"); 1007 return rv; 1008 } 1009 /** 1010 * Demarshall values from a buffer. 1011 * @param sig The D-Bus signature(s) of the value(s). 1012 * @param buf The buffer to demarshall from. 1013 * @param ofs The offset into the data buffer to start. 1014 * @return The demarshalled value(s). 1015 */ extract(String sig, byte[] buf, int ofs)1016 public Object[] extract(String sig, byte[] buf, int ofs) throws DBusException 1017 { 1018 return extract(sig, buf, new int[] { 0, ofs }); 1019 } 1020 /** 1021 * Demarshall values from a buffer. 1022 * @param sig The D-Bus signature(s) of the value(s). 1023 * @param buf The buffer to demarshall from. 1024 * @param ofs An array of two ints, the offset into the signature 1025 * and the offset into the data buffer. These values will be 1026 * updated to the start of the next value ofter demarshalling. 1027 * @return The demarshalled value(s). 1028 */ extract(String sig, byte[] buf, int[] ofs)1029 public Object[] extract(String sig, byte[] buf, int[] ofs) throws DBusException 1030 { 1031 if (Debug.debug) Debug.print(Debug.VERBOSE, "extract("+sig+",#"+buf.length+", {"+ofs[0]+","+ofs[1]+"}"); 1032 Vector<Object> rv = new Vector<Object>(); 1033 byte[] sigb = sig.getBytes(); 1034 for (int[] i = ofs; i[0] < sigb.length; i[0]++) { 1035 rv.add(extractone(sigb, buf, i, false)); 1036 } 1037 return rv.toArray(); 1038 } 1039 /** 1040 * Returns the Bus ID that sent the message. 1041 */ getSource()1042 public String getSource() { return (String) headers.get(HeaderField.SENDER); } 1043 /** 1044 * Returns the destination of the message. 1045 */ getDestination()1046 public String getDestination() { return (String) headers.get(HeaderField.DESTINATION); } 1047 /** 1048 * Returns the interface of the message. 1049 */ getInterface()1050 public String getInterface() { return (String) headers.get(HeaderField.INTERFACE); } 1051 /** 1052 * Returns the object path of the message. 1053 */ getPath()1054 public String getPath() 1055 { 1056 Object o = headers.get(HeaderField.PATH); 1057 if (null == o) return null; 1058 return o.toString(); 1059 } 1060 /** 1061 * Returns the member name or error name this message represents. 1062 */ getName()1063 public String getName() 1064 { 1065 if (this instanceof Error) 1066 return (String) headers.get(HeaderField.ERROR_NAME); 1067 else 1068 return (String) headers.get(HeaderField.MEMBER); 1069 } 1070 /** 1071 * Returns the dbus signature of the parameters. 1072 */ getSig()1073 public String getSig() { return (String) headers.get(HeaderField.SIGNATURE); } 1074 /** 1075 * Returns the message flags. 1076 */ getFlags()1077 public int getFlags() { return flags; } 1078 /** 1079 * Returns the message serial ID (unique for this connection) 1080 * @return the message serial. 1081 */ getSerial()1082 public long getSerial() { return serial; } 1083 /** 1084 * If this is a reply to a message, this returns its serial. 1085 * @return The reply serial, or 0 if it is not a reply. 1086 */ getReplySerial()1087 public long getReplySerial() 1088 { 1089 Number l = (Number) headers.get(HeaderField.REPLY_SERIAL); 1090 if (null == l) return 0; 1091 return l.longValue(); 1092 } 1093 /** 1094 * Parses and returns the parameters to this message as an Object array. 1095 */ getParameters()1096 public Object[] getParameters() throws DBusException 1097 { 1098 if (null == args && null != body) { 1099 String sig = (String) headers.get(HeaderField.SIGNATURE); 1100 if (null != sig && 0 != body.length) { 1101 args = extract(sig, body, 0); 1102 } else args = new Object[0]; 1103 } 1104 return args; 1105 } setArgs(Object[] args)1106 protected void setArgs(Object[] args) { this.args = args; } 1107 /** 1108 * Warning, do not use this method unless you really know what you are doing. 1109 */ setSource(String source)1110 public void setSource(String source) throws DBusException 1111 { 1112 if (null != body) { 1113 wiredata = new byte[BUFFERINCREMENT][]; 1114 bufferuse = 0; 1115 bytecounter = 0; 1116 preallocate(12); 1117 append("yyyyuu", big ? Endian.BIG : Endian.LITTLE, type, flags, protover, bodylen, serial); 1118 headers.put(HeaderField.SENDER, source); 1119 Object[][] newhead = new Object[headers.size()][]; 1120 int i = 0; 1121 for (Byte b: headers.keySet()) { 1122 newhead[i] = new Object[2]; 1123 newhead[i][0] = b; 1124 newhead[i][1] = headers.get(b); 1125 i++; 1126 } 1127 append("a(yv)", (Object) newhead); 1128 pad((byte) 8); 1129 appendBytes(body); 1130 } 1131 } 1132 } 1133