/* D-Bus Java Implementation Copyright (c) 2005-2006 Matthew Johnson This program is free software; you can redistribute it and/or modify it under the terms of either the GNU Lesser General Public License Version 2 or the Academic Free Licence Version 2.1. Full licence texts are included in the COPYING file with this program. Modified to suit Jolie/DBus protocol implementation by Tobias Mandrup Johansen */ package jolie.runtime.typing; import cx.ath.matthew.debug.Debug; import cx.ath.matthew.utils.Hexdump; import java.io.UnsupportedEncodingException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Vector; import jolie.lang.parse.ast.types.UInt32; import jolie.lang.parse.ast.types.UInt16; import jolie.lang.parse.ast.types.UInt64; import jolie.net.dbus.Marshalling; import jolie.runtime.Value; import jolie.runtime.ValueVector; import org.freedesktop.dbus.exceptions.DBusException; import org.freedesktop.dbus.exceptions.MarshallingException; import org.freedesktop.dbus.exceptions.UnknownTypeCodeException; import jolie.net.dbus.Message; import org.freedesktop.dbus.AbstractConnection; import org.freedesktop.dbus.Variant; public class JolieDBusUtils { static final int MAX_ARRAY_LENGTH = 67108864; static final int MAX_NAME_LENGTH = 255; /** * Demarshall values from a buffer. * * @param sig The D-Bus signature(s) of the value(s). * @param buf The buffer to demarshall from. * @param ofs An array of two ints, the offset into the signature and the * offset into the data buffer. These values will be updated to the start of * the next value ofter demarshalling. * @return The demarshalled value(s). */ public static Object[] extract(String sig, byte[] buf, byte endian, int[] ofs) throws DBusException { if (Debug.debug) { Debug.print(Debug.VERBOSE, "extract(" + sig + ",#" + buf.length + ", {" + ofs[0] + "," + ofs[1] + "}"); } //System.out.println("extract(" + sig + ",#" + buf.length + ", {" + ofs[0] + "," + ofs[1] + "}"); Vector<Object> rv = new Vector<Object>(); byte[] sigb = sig.getBytes(); for (int[] i = ofs; i[0] < sigb.length; i[0]++) { rv.add(extractone(sigb, buf, endian, i, false)); } return rv.toArray(); } /** * Demarshall one value from a buffer. * @param sigb A buffer of the D-Bus signature. * @param buf The buffer to demarshall from. * @param ofs An array of two ints, the offset into the signature buffer and * the offset into the data buffer. These values will be updated to the * start of the next value ofter demarshalling. * @param contained converts nested arrays to Lists * @return The demarshalled value. */ private static Object extractone(byte[] sigb, byte[] buf, byte endian, int[] ofs, boolean contained) throws DBusException { if (Debug.debug) { Debug.print(Debug.VERBOSE, "Extracting type: " + ((char) sigb[ofs[0]]) + " from offset " + ofs[1]); } //System.out.println("Extracting type: " + ((char) sigb[ofs[0]]) + " from offset " + ofs[1]); Object rv = null; ofs[1] = align(ofs[1], sigb[ofs[0]]); switch (sigb[ofs[0]]) { case Message.ArgumentType.BYTE: rv = buf[ofs[1]++]; break; case Message.ArgumentType.UINT32: rv = new UInt32(Message.demarshallint(buf, ofs[1], endian, 4)); ofs[1] += 4; break; case Message.ArgumentType.INT32: rv = (int) Message.demarshallint(buf, ofs[1], endian, 4); ofs[1] += 4; break; case Message.ArgumentType.INT16: rv = (short) Message.demarshallint(buf, ofs[1], endian, 2); ofs[1] += 2; break; case Message.ArgumentType.UINT16: rv = new UInt16((int) Message.demarshallint(buf, ofs[1], endian, 2)); ofs[1] += 2; break; case Message.ArgumentType.INT64: rv = Message.demarshallint(buf, ofs[1], endian, 8); ofs[1] += 8; break; case Message.ArgumentType.UINT64: long top; long bottom; if (endian == Message.Endian.BIG) { top = Message.demarshallint(buf, ofs[1], endian, 4); ofs[1] += 4; bottom = Message.demarshallint(buf, ofs[1], endian, 4); } else { bottom = Message.demarshallint(buf, ofs[1], endian, 4); ofs[1] += 4; top = Message.demarshallint(buf, ofs[1], endian, 4); } rv = new UInt64(top, bottom); ofs[1] += 4; break; case Message.ArgumentType.DOUBLE: long l = Message.demarshallint(buf, ofs[1], endian, 8); ofs[1] += 8; rv = Double.longBitsToDouble(l); break; case Message.ArgumentType.FLOAT: int rf = (int) Message.demarshallint(buf, ofs[1], endian, 4); ofs[1] += 4; rv = Float.intBitsToFloat(rf); break; case Message.ArgumentType.BOOLEAN: rf = (int) Message.demarshallint(buf, ofs[1], endian, 4); ofs[1] += 4; rv = (1 == rf) ? Boolean.TRUE : Boolean.FALSE; break; case Message.ArgumentType.ARRAY: long size = Message.demarshallint(buf, ofs[1], endian, 4); if (Debug.debug) { Debug.print(Debug.VERBOSE, "Reading array of size: " + size); } //System.out.println("Reading array of size: " + size); ofs[1] += 4; byte algn = (byte) Message.getAlignment(sigb[++ofs[0]]); ofs[1] = align(ofs[1], sigb[ofs[0]]); int length = (int) (size / algn); if (length > MAX_ARRAY_LENGTH) { throw new MarshallingException("Arrays must not exceed " + MAX_ARRAY_LENGTH); // optimise primatives } switch (sigb[ofs[0]]) { case Message.ArgumentType.BYTE: rv = new byte[length]; System.arraycopy(buf, ofs[1], rv, 0, length); ofs[1] += size; break; case Message.ArgumentType.INT16: rv = new short[length]; for (int j = 0; j < length; j++, ofs[1] += algn) { ((short[]) rv)[j] = (short) Message.demarshallint(buf, ofs[1], endian, algn); } break; case Message.ArgumentType.INT32: rv = new int[length]; for (int j = 0; j < length; j++, ofs[1] += algn) { ((int[]) rv)[j] = (int) Message.demarshallint(buf, ofs[1], endian, algn); } break; case Message.ArgumentType.INT64: rv = new long[length]; for (int j = 0; j < length; j++, ofs[1] += algn) { ((long[]) rv)[j] = Message.demarshallint(buf, ofs[1], endian, algn); } break; case Message.ArgumentType.BOOLEAN: rv = new boolean[length]; for (int j = 0; j < length; j++, ofs[1] += algn) { ((boolean[]) rv)[j] = (1 == Message.demarshallint(buf, ofs[1], endian, algn)); } break; case Message.ArgumentType.FLOAT: rv = new float[length]; for (int j = 0; j < length; j++, ofs[1] += algn) { ((float[]) rv)[j] = Float.intBitsToFloat((int) Message.demarshallint(buf, ofs[1], endian, algn)); } break; case Message.ArgumentType.DOUBLE: rv = new double[length]; for (int j = 0; j < length; j++, ofs[1] += algn) { ((double[]) rv)[j] = Double.longBitsToDouble(Message.demarshallint(buf, ofs[1], endian, algn)); } break; case Message.ArgumentType.DICT_ENTRY1: if (0 == size) { // advance the type parser even on 0-size arrays. Vector<java.lang.reflect.Type> temp = new Vector<java.lang.reflect.Type>(); byte[] temp2 = new byte[sigb.length - ofs[0]]; System.arraycopy(sigb, ofs[0], temp2, 0, temp2.length); String temp3 = new String(temp2); // ofs[0] gets incremented anyway. Leave one character on the stack int temp4 = Marshalling.getJavaType(temp3, temp, 1) - 1; ofs[0] += temp4; if (Debug.debug) { Debug.print(Debug.VERBOSE, "Aligned type: " + temp3 + " " + temp4 + " " + ofs[0]); } //System.out.println("Aligned type: " + temp3 + " " + temp4 + " " + ofs[0]); } int ofssave = ofs[0]; long end = ofs[1] + size; Vector<Object[]> entries = new Vector<Object[]>(); while (ofs[1] < end) { ofs[0] = ofssave; entries.add((Object[]) extractone(sigb, buf, endian, ofs, true)); } rv = entries; //rv = new DBusMap<Object, Object>(entries.toArray(new Object[0][])); break; default: if (0 == size) { // advance the type parser even on 0-size arrays. Vector<java.lang.reflect.Type> temp = new Vector<java.lang.reflect.Type>(); byte[] temp2 = new byte[sigb.length - ofs[0]]; System.arraycopy(sigb, ofs[0], temp2, 0, temp2.length); String temp3 = new String(temp2); // ofs[0] gets incremented anyway. Leave one character on the stack int temp4 = Marshalling.getJavaType(temp3, temp, 1) - 1; ofs[0] += temp4; if (Debug.debug) { Debug.print(Debug.VERBOSE, "Aligned type: " + temp3 + " " + temp4 + " " + ofs[0]); } //System.out.println("Aligned type: " + temp3 + " " + temp4 + " " + ofs[0]); } ofssave = ofs[0]; end = ofs[1] + size; Vector<Object> contents = new Vector<Object>(); while (ofs[1] < end) { ofs[0] = ofssave; contents.add(extractone(sigb, buf, endian, ofs, true)); } rv = contents; } if (contained && !(rv instanceof List) && !(rv instanceof Map)) { //rv = ArrayFrob.listify(rv); } break; case Message.ArgumentType.STRUCT1: Vector<Object> contents = new Vector<Object>(); while (sigb[++ofs[0]] != Message.ArgumentType.STRUCT2) { contents.add(extractone(sigb, buf, endian, ofs, true)); } rv = contents.toArray(); break; case Message.ArgumentType.DICT_ENTRY1: Object[] decontents = new Object[2]; 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])); } //System.out.println("Extracting Dict Entry (" + Hexdump.toAscii(sigb, ofs[0], sigb.length - ofs[0]) + ") from: " + Hexdump.toHex(buf, ofs[1], buf.length - ofs[1])); ofs[0]++; decontents[0] = extractone(sigb, buf, endian, ofs, true); ofs[0]++; decontents[1] = extractone(sigb, buf, endian, ofs, true); ofs[0]++; rv = decontents; break; case Message.ArgumentType.VARIANT: int[] newofs = new int[]{0, ofs[1]}; String sig = (String) extract(Message.ArgumentType.SIGNATURE_STRING, buf, endian, newofs)[0]; newofs[0] = 0; rv = new Variant<Object>(extract(sig, buf, endian, newofs)[0], sig); ofs[1] = newofs[1]; break; case Message.ArgumentType.STRING: length = (int) Message.demarshallint(buf, ofs[1], endian, 4); ofs[1] += 4; try { rv = new String(buf, ofs[1], length, "UTF-8"); } catch (UnsupportedEncodingException UEe) { if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) { Debug.print(UEe); } throw new DBusException("System does not support UTF-8 encoding"); } ofs[1] += length + 1; break; case Message.ArgumentType.OBJECT_PATH: length = (int) Message.demarshallint(buf, ofs[1], endian, 4); ofs[1] += 4; //rv = new ObjectPath(getSource(), new String(buf, ofs[1], length)); rv = new String(buf, ofs[1], length); ofs[1] += length + 1; break; case Message.ArgumentType.SIGNATURE: length = (buf[ofs[1]++] & 0xFF); rv = new String(buf, ofs[1], length); ofs[1] += length + 1; break; default: throw new UnknownTypeCodeException(sigb[ofs[0]]); } if (Debug.debug) { if (rv instanceof Object[]) { Debug.print(Debug.VERBOSE, "Extracted: " + Arrays.deepToString((Object[]) rv) + " (now at " + ofs[1] + ")"); } else { Debug.print(Debug.VERBOSE, "Extracted: " + rv + " (now at " + ofs[1] + ")"); } } if (rv instanceof Object[]) { //System.out.println("Extracted: " + Arrays.deepToString((Object[]) rv) + " (now at " + ofs[1] + ")"); } else { //System.out.println("Extracted: " + rv + " (now at " + ofs[1] + ")"); } return rv; } public static Value extract(String sig, byte[] buf, byte endian, int[] ofs,Type requestType) throws DBusException { if (Debug.debug) { Debug.print(Debug.VERBOSE, "extract(" + sig + ",#" + buf.length + ", {" + ofs[0] + "," + ofs[1] + "}"); } //System.out.println("extract(" + sig + ",#" + buf.length + ", {" + ofs[0] + "," + ofs[1] + "}"); Value rv = Value.create(); //ValueVector vv = ValueVector.create(); Map<String,ValueVector> children = rv.children(); byte[] sigb = sig.getBytes(); List<Map.Entry<String,Type>> subtypes = new LinkedList<Map.Entry<String,Type>>(); Set<Map.Entry<String,Type>> hashSubtypes; if(requestType != null){ try{ java.lang.reflect.Method subTypesMethod = Type.class.getDeclaredMethod("subTypeSet"); subTypesMethod.setAccessible(true); hashSubtypes = (Set<Map.Entry<String,Type>>)subTypesMethod.invoke(requestType); } catch(NoSuchMethodException nme){ throw new DBusException(nme.getMessage()); } catch (IllegalAccessException iae){ throw new DBusException(iae.getMessage()); } catch (InvocationTargetException ite){ throw new DBusException(ite.getMessage()); } subtypes.addAll(hashSubtypes); //sort the list. Collections.sort(subtypes, new Comparator<Map.Entry<String,Type>>(){ @Override public int compare(Map.Entry<String,Type> o1, Map.Entry<String,Type> o2) { return o1.getKey().compareTo(o2.getKey()); } }); } int counter = 0; for (int[] i = ofs; i[0] < sigb.length; i[0]++) { if(!subtypes.isEmpty() && subtypes.get(counter) != null){ Object val = extractone(sigb, buf, endian, i, false,subtypes.get(counter).getValue(),subtypes.get(counter).getKey()); if(val instanceof Value){ ValueVector vv = ValueVector.create(); vv.set(0, (Value)val); children.put(subtypes.get(counter).getKey(), vv); } else { children.put(subtypes.get(counter).getKey(), (ValueVector)val); } counter++; } else { rv = (Value)extractone(sigb, buf, endian, i, false, requestType,""); } } return rv; } private static Object extractone(byte[] sigb, byte[] buf, byte endian, int[] ofs, boolean contained,jolie.runtime.typing.Type requestType,String name) throws DBusException { Object rv = null; ofs[1] = align(ofs[1], sigb[ofs[0]]); List<Map.Entry<String,jolie.runtime.typing.Type>> subtypes; Map<String,ValueVector> children; switch (sigb[ofs[0]]) { case Message.ArgumentType.BYTE: rv = Value.create(buf[ofs[1]++]); break; case Message.ArgumentType.UINT32: rv = Value.create(new UInt32(Message.demarshallint(buf, ofs[1], endian, 4))); ofs[1] += 4; break; case Message.ArgumentType.INT32: rv = Value.create((int) Message.demarshallint(buf, ofs[1], endian, 4)); ofs[1] += 4; break; case Message.ArgumentType.INT16: rv = Value.create((short) Message.demarshallint(buf, ofs[1], endian, 2)); ofs[1] += 2; break; case Message.ArgumentType.UINT16: rv = Value.create(new UInt16((int) Message.demarshallint(buf, ofs[1], endian, 2))); ofs[1] += 2; break; case Message.ArgumentType.INT64: rv = Value.create(Message.demarshallint(buf, ofs[1], endian, 8)); ofs[1] += 8; break; case Message.ArgumentType.UINT64: long top; long bottom; if (endian == Message.Endian.BIG) { top = Message.demarshallint(buf, ofs[1], endian, 4); ofs[1] += 4; bottom = Message.demarshallint(buf, ofs[1], endian, 4); } else { bottom = Message.demarshallint(buf, ofs[1], endian, 4); ofs[1] += 4; top = Message.demarshallint(buf, ofs[1], endian, 4); } rv = Value.create(new UInt64(top, bottom)); ofs[1] += 4; break; case Message.ArgumentType.DOUBLE: long l = Message.demarshallint(buf, ofs[1], endian, 8); ofs[1] += 8; rv = Value.create(Double.longBitsToDouble(l)); break; case Message.ArgumentType.FLOAT: ofs[1] += 4; //rv = Value.create(Float.intBitsToFloat((int) Message.demarshallint(buf, ofs[1], endian, algn))); break; case Message.ArgumentType.BOOLEAN: int rf = (int) Message.demarshallint(buf, ofs[1], endian, 4); ofs[1] += 4; rv = (1 == rf) ? Value.create(Boolean.TRUE) : Value.create(Boolean.FALSE); break; case Message.ArgumentType.ARRAY: long size = Message.demarshallint(buf, ofs[1], endian, 4); Value val = null; ValueVector vv = null; if (Debug.debug) { Debug.print(Debug.VERBOSE, "Reading array of size: " + size); } //System.out.println("Reading array of size: " + size); ofs[1] += 4; byte algn = (byte) Message.getAlignment(sigb[++ofs[0]]); ofs[1] = align(ofs[1], sigb[ofs[0]]); int length = (int) (size / algn); int counter; ValueVector arrayVV; if (length > MAX_ARRAY_LENGTH) { throw new MarshallingException("Arrays must not exceed " + MAX_ARRAY_LENGTH); // optimise primatives } switch (sigb[ofs[0]]) { case Message.ArgumentType.BYTE: byte[] byteArray = new byte[length]; System.arraycopy(buf, ofs[1], byteArray, 0, length); vv = ValueVector.create(); for(int i = 0; i < byteArray.length;i++){ //val.add(Value.create(new ByteArray(new byte[]{byteArray[i]}))); vv.set(i,Value.create((byte)byteArray[i])); } ofs[1] += size; rv = vv; break; case Message.ArgumentType.INT16: rv = new short[length]; vv = ValueVector.create(); for (int j = 0; j < length; j++, ofs[1] += algn) { //((short[]) rv)[j] = (short) Message.demarshallint(buf, ofs[1], endian, algn); vv.set(j,Value.create((short) Message.demarshallint(buf, ofs[1], endian, algn))); } rv = vv; break; case Message.ArgumentType.INT32: vv = ValueVector.create(); for (int j = 0; j < length; j++, ofs[1] += algn) { vv.set(j,Value.create((int) Message.demarshallint(buf, ofs[1], endian, algn))); } rv = vv; break; case Message.ArgumentType.INT64: vv = ValueVector.create(); for (int j = 0; j < length; j++, ofs[1] += algn) { vv.set(j,Value.create(Message.demarshallint(buf, ofs[1], endian, algn))); } rv = vv; break; case Message.ArgumentType.BOOLEAN: vv = ValueVector.create(); for (int j = 0; j < length; j++, ofs[1] += algn) { vv.set(j,Value.create(1 == Message.demarshallint(buf,ofs[1], endian, algn))); } rv = vv; break; case Message.ArgumentType.FLOAT: vv = ValueVector.create(); for (int j = 0; j < length; j++, ofs[1] += algn) { Float fl = Float.intBitsToFloat((int) Message.demarshallint(buf, ofs[1], endian, algn)); vv.set(j,Value.create(fl.doubleValue())); } rv = vv; break; case Message.ArgumentType.DOUBLE: vv = ValueVector.create(); for (int j = 0; j < length; j++, ofs[1] += algn) { vv.set(j,Value.create(Double.longBitsToDouble(Message.demarshallint(buf, ofs[1], endian, algn)))); } rv = vv; break; case Message.ArgumentType.DICT_ENTRY1: if (0 == size) { // advance the type parser even on 0-size arrays. Vector<java.lang.reflect.Type> temp = new Vector<java.lang.reflect.Type>(); byte[] temp2 = new byte[sigb.length - ofs[0]]; System.arraycopy(sigb, ofs[0], temp2, 0, temp2.length); String temp3 = new String(temp2); // ofs[0] gets incremented anyway. Leave one character on the stack int temp4 = Marshalling.getJavaType(temp3, temp, 1) - 1; ofs[0] += temp4; if (Debug.debug) { Debug.print(Debug.VERBOSE, "Aligned type: " + temp3 + " " + temp4 + " " + ofs[0]); } //System.out.println("Aligned type: " + temp3 + " " + temp4 + " " + ofs[0]); } int ofssave = ofs[0]; long end = ofs[1] + size; Set<Map.Entry<String, jolie.runtime.typing.Type>> subTypeSet; try{ Method typeImplMethod = Type.class.getDeclaredMethod("subTypeSet"); typeImplMethod.setAccessible(true); subTypeSet = (Set<Map.Entry<String, Type>>)typeImplMethod.invoke(requestType); } catch(NoSuchMethodException nsme){ throw new DBusException(nsme.toString()); } catch(IllegalAccessException iae) { throw new DBusException(iae.toString()); } catch(IllegalArgumentException ia){ throw new DBusException(ia.toString()); } catch(InvocationTargetException ite){ throw new DBusException(ite.toString());} subtypes = new LinkedList<Map.Entry<String, jolie.runtime.typing.Type>>(); if(requestType != null && subTypeSet != null){ subtypes.addAll(subTypeSet); //sort the list. Collections.sort(subtypes, new Comparator<Map.Entry<String,jolie.runtime.typing.Type>>(){ @Override public int compare(Map.Entry<String, jolie.runtime.typing.Type> o1, Map.Entry<String, jolie.runtime.typing.Type> o2) { return o1.getKey().compareTo(o2.getKey()); } }); } counter = 0; arrayVV = ValueVector.create(); while (ofs[1] < end) { ofs[0] = ofssave; if(subtypes.size() > 0){ arrayVV.set(counter,(Value)extractone(sigb, buf, endian, ofs, true,requestType,name)); } else { arrayVV.set(counter, (Value)extractone(sigb, buf, endian, ofs, true,null,null)); } counter++; } rv = arrayVV; break; default: if (0 == size) { // advance the type parser even on 0-size arrays. Vector<java.lang.reflect.Type> temp = new Vector<java.lang.reflect.Type>(); byte[] temp2 = new byte[sigb.length - ofs[0]]; System.arraycopy(sigb, ofs[0], temp2, 0, temp2.length); String temp3 = new String(temp2); // ofs[0] gets incremented anyway. Leave one character on the stack int temp4 = Marshalling.getJavaType(temp3, temp, 1) - 1; ofs[0] += temp4; if (Debug.debug) { Debug.print(Debug.VERBOSE, "Aligned type: " + temp3 + " " + temp4 + " " + ofs[0]); } //System.out.println("Aligned type: " + temp3 + " " + temp4 + " " + ofs[0]); } ofssave = ofs[0]; end = ofs[1] + size; subtypes = new LinkedList<Map.Entry<String, Type>>(); try{ Method typeImplMethod = Type.class.getDeclaredMethod("subTypeSet"); typeImplMethod.setAccessible(true); subTypeSet = (Set<Map.Entry<String, Type>>)typeImplMethod.invoke(requestType); } catch(NoSuchMethodException nsme){ throw new DBusException(nsme.toString()); } catch(IllegalAccessException iae) { throw new DBusException(iae.toString()); } catch(IllegalArgumentException ia){ throw new DBusException(ia.toString()); } catch(InvocationTargetException ite){ throw new DBusException(ite.toString());} if(requestType != null && subTypeSet != null){ subtypes.addAll(subTypeSet); //sort the list. Collections.sort(subtypes, new Comparator<Map.Entry<String,jolie.runtime.typing.Type>>(){ @Override public int compare(Map.Entry<String, jolie.runtime.typing.Type> o1, Map.Entry<String, jolie.runtime.typing.Type> o2) { return o1.getKey().compareTo(o2.getKey()); } }); } counter = 0; arrayVV = ValueVector.create(); while (ofs[1] < end) { ofs[0] = ofssave; if(subtypes.size() > 0){ Object extracted = extractone(sigb, buf, endian, ofs, true,requestType,name); if(extracted instanceof Value){ arrayVV.set(counter, (Value)extracted); } else if (extracted instanceof ValueVector) { Value newVal = Value.create(); newVal.children().put(name, (ValueVector)extracted); arrayVV.set(counter,newVal); } } else { arrayVV.set(counter, (Value)extractone(sigb, buf, endian, ofs, true,null,null)); } counter++; } rv = arrayVV; } break; case Message.ArgumentType.STRUCT1: //Vector<Object> contents = new Vector<Object>(); val = Value.create(); children = val.children(); Set<Map.Entry<String, jolie.runtime.typing.Type>> subTypeSet; subtypes = new LinkedList<Map.Entry<String, Type>>(); try { Method typeImplMethod = Type.class.getDeclaredMethod("subTypeSet"); typeImplMethod.setAccessible(true); subTypeSet = (Set<Map.Entry<String, Type>>) typeImplMethod.invoke(requestType); } catch (NoSuchMethodException nsme) { throw new DBusException(nsme.toString()); } catch (IllegalAccessException iae) { throw new DBusException(iae.toString()); } catch (IllegalArgumentException ia) { throw new DBusException(ia.toString()); } catch (InvocationTargetException ite) { throw new DBusException(ite.toString()); } if (requestType != null && subTypeSet != null) { subtypes.addAll(subTypeSet); //sort the list. Collections.sort(subtypes, new Comparator<Map.Entry<String, jolie.runtime.typing.Type>>() { @Override public int compare(Map.Entry<String, jolie.runtime.typing.Type> o1, Map.Entry<String, jolie.runtime.typing.Type> o2) { return o1.getKey().compareTo(o2.getKey()); } }); } counter = 0; Object returnVal; while (sigb[++ofs[0]] != Message.ArgumentType.STRUCT2) { if(subtypes.size() > 1){ returnVal = extractone(sigb, buf, endian, ofs, false,subtypes.get(counter).getValue(),subtypes.get(counter).getKey()); if(returnVal instanceof Value){ vv = ValueVector.create(); vv.set(0, (Value)returnVal); children.put(subtypes.get(counter).getKey(), vv); } else { children.put(subtypes.get(counter).getKey(), (ValueVector)returnVal); } }else if (subtypes.size() == 1){ returnVal = extractone(sigb, buf, endian, ofs, false,subtypes.get(0).getValue(),subtypes.get(0).getKey()); if(returnVal instanceof Value){ vv = ValueVector.create(); vv.set(0, (Value)returnVal); children.put(subtypes.get(0).getKey(), vv); } else { children.put(subtypes.get(0).getKey(), (ValueVector)returnVal); } } else { returnVal = extractone(sigb, buf, endian, ofs, false,requestType,name); if(returnVal instanceof Value){ vv = ValueVector.create(); vv.set(0, (Value)returnVal); children.put(name, vv); } else { children.put(name, (ValueVector)returnVal); } } counter++; } rv = val; break; case Message.ArgumentType.DICT_ENTRY1: 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])); } subtypes = new LinkedList<Map.Entry<String, Type>>(); try { Method typeImplMethod = Type.class.getDeclaredMethod("subTypeSet"); typeImplMethod.setAccessible(true); subTypeSet = (Set<Map.Entry<String, Type>>) typeImplMethod.invoke(requestType); } catch (NoSuchMethodException nsme) { throw new DBusException(nsme.toString()); } catch (IllegalAccessException iae) { throw new DBusException(iae.toString()); } catch (IllegalArgumentException ia) { throw new DBusException(ia.toString()); } catch (InvocationTargetException ite) { throw new DBusException(ite.toString()); } if (requestType != null && subTypeSet != null) { subtypes.addAll(subTypeSet); //sort the list. Collections.sort(subtypes, new Comparator<Map.Entry<String, jolie.runtime.typing.Type>>() { @Override public int compare(Map.Entry<String, jolie.runtime.typing.Type> o1, Map.Entry<String, jolie.runtime.typing.Type> o2) { return o1.getKey().compareTo(o2.getKey()); } }); } if(subtypes.size() == 2){ ofs[0]++; Object key = (extractone(sigb, buf, endian, ofs, false,subtypes.get(0).getValue(),subtypes.get(0).getKey())); ofs[0]++; Object tempval = extractone(sigb, buf, endian, ofs, false,subtypes.get(1).getValue(),subtypes.get(1).getKey()); Value entry = Value.create(); children = entry.children(); if(key instanceof Value){ ValueVector keyVector = ValueVector.create(); keyVector.set(0, (Value)key); children.put("key", keyVector); } else if (key instanceof ValueVector){ children.put("key", (ValueVector)key); } if(tempval instanceof Value){ ValueVector valueVec = ValueVector.create(); valueVec.set(0, (Value)tempval); children.put("value", valueVec); } else if (tempval instanceof ValueVector){ children.put("value", (ValueVector)tempval); } rv = entry; } ofs[0]++; break; case Message.ArgumentType.VARIANT: int[] newofs = new int[]{0, ofs[1]}; String sig = (String) extract(Message.ArgumentType.SIGNATURE_STRING, buf, endian, newofs)[0]; newofs[0] = 0; //rv = new Variant<Object>(extract(sig, buf, endian, newofs)[0], sig); rv = null; ofs[1] = newofs[1]; break; case Message.ArgumentType.STRING: length = (int) Message.demarshallint(buf, ofs[1], endian, 4); ofs[1] += 4; try { rv = Value.create(new String(buf, ofs[1], length, "UTF-8")); } catch (UnsupportedEncodingException UEe) { if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) { Debug.print(UEe); } throw new DBusException("System does not support UTF-8 encoding"); } ofs[1] += length + 1; break; default: throw new UnknownTypeCodeException(sigb[ofs[0]]); } return rv; } /** * Align a counter to the given type. * * @param current The current counter. * @param type The type to align to. * @return The new, aligned, counter. */ public static int align(int current, byte type) { if (Debug.debug) { Debug.print(Debug.VERBOSE, "aligning to " + (char) type); } //System.out.println("aligning to " + (char) type); int a = Message.getAlignment(type); if (0 == (current % a)) { return current; } return current + (a - (current % a)); } }