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