/* 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. */ package org.freedesktop.dbus; import cx.ath.matthew.debug.Debug; import cx.ath.matthew.utils.Hexdump; import org.freedesktop.dbus.exceptions.DBusException; import org.freedesktop.dbus.exceptions.MessageProtocolVersionException; import org.freedesktop.dbus.exceptions.MessageTypeException; import java.io.BufferedInputStream; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.net.SocketTimeoutException; import java.text.MessageFormat; import static org.freedesktop.dbus.Gettext.getString; public class MessageReader { private InputStream in; private byte[] buf = null; private byte[] tbuf = null; private byte[] header = null; private byte[] body = null; private int[] len = new int[4]; public MessageReader(InputStream in) { this.in = new BufferedInputStream(in); } public Message readMessage() throws IOException, DBusException { int rv; /* Read the 12 byte fixed header, retrying as neccessary */ if (null == buf) { buf = new byte[12]; len[0] = 0; } if (len[0] < 12) { try { rv = in.read(buf, len[0], 12 - len[0]); } catch (SocketTimeoutException STe) { return null; } if (-1 == rv) throw new EOFException(getString("transportReturnedEOF")); len[0] += rv; } if (len[0] == 0) return null; if (len[0] < 12) { if (Debug.debug) Debug.print(Debug.DEBUG, "Only got " + len[0] + " of 12 bytes of header"); return null; } /* Parse the details from the header */ byte endian = buf[0]; byte type = buf[1]; byte protover = buf[3]; if (protover > Message.PROTOCOL) { buf = null; throw new MessageProtocolVersionException(MessageFormat.format(getString("protocolVersionUnsupported"), new Object[]{protover})); } /* Read the length of the variable header */ if (null == tbuf) { tbuf = new byte[4]; len[1] = 0; } if (len[1] < 4) { try { rv = in.read(tbuf, len[1], 4 - len[1]); } catch (SocketTimeoutException STe) { return null; } if (-1 == rv) throw new EOFException(getString("transportReturnedEOF")); len[1] += rv; } if (len[1] < 4) { if (Debug.debug) Debug.print(Debug.DEBUG, "Only got " + len[1] + " of 4 bytes of header"); return null; } /* Parse the variable header length */ int headerlen = 0; if (null == header) { headerlen = (int) Message.demarshallint(tbuf, 0, endian, 4); if (0 != headerlen % 8) headerlen += 8 - (headerlen % 8); } else headerlen = header.length - 8; /* Read the variable header */ if (null == header) { header = new byte[headerlen + 8]; System.arraycopy(tbuf, 0, header, 0, 4); len[2] = 0; } if (len[2] < headerlen) { try { rv = in.read(header, 8 + len[2], headerlen - len[2]); } catch (SocketTimeoutException STe) { return null; } if (-1 == rv) throw new EOFException(getString("transportReturnedEOF")); len[2] += rv; } if (len[2] < headerlen) { if (Debug.debug) Debug.print(Debug.DEBUG, "Only got " + len[2] + " of " + headerlen + " bytes of header"); return null; } /* Read the body */ int bodylen = 0; if (null == body) bodylen = (int) Message.demarshallint(buf, 4, endian, 4); if (null == body) { body = new byte[bodylen]; len[3] = 0; } if (len[3] < body.length) { try { rv = in.read(body, len[3], body.length - len[3]); } catch (SocketTimeoutException STe) { return null; } if (-1 == rv) throw new EOFException(getString("transportReturnedEOF")); len[3] += rv; } if (len[3] < body.length) { if (Debug.debug) Debug.print(Debug.DEBUG, "Only got " + len[3] + " of " + body.length + " bytes of body"); return null; } Message m; switch (type) { case Message.MessageType.METHOD_CALL: m = new MethodCall(); break; case Message.MessageType.METHOD_RETURN: m = new MethodReturn(); break; case Message.MessageType.SIGNAL: m = new DBusSignal(); break; case Message.MessageType.ERROR: m = new Error(); break; default: throw new MessageTypeException(MessageFormat.format(getString("messageTypeUnsupported"), new Object[]{type})); } if (Debug.debug) { Debug.print(Debug.VERBOSE, Hexdump.format(buf)); Debug.print(Debug.VERBOSE, Hexdump.format(tbuf)); Debug.print(Debug.VERBOSE, Hexdump.format(header)); Debug.print(Debug.VERBOSE, Hexdump.format(body)); } try { m.populate(buf, header, body); } catch (DBusException DBe) { if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, DBe); buf = null; tbuf = null; body = null; header = null; throw DBe; } catch (RuntimeException Re) { if (AbstractConnection.EXCEPTION_DEBUG && Debug.debug) Debug.print(Debug.ERR, Re); buf = null; tbuf = null; body = null; header = null; throw Re; } if (Debug.debug) { Debug.print(Debug.INFO, "=> " + m); } buf = null; tbuf = null; body = null; header = null; return m; } public void close() throws IOException { if (Debug.debug) Debug.print(Debug.INFO, "Closing Message Reader"); in.close(); } }