| /******************************************************************************* |
| * Copyright (c) 2000, 2011 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdi.internal.jdwp; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.DataInputStream; |
| import java.io.IOException; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Modifier; |
| |
| /** |
| * This class implements the corresponding Java Debug Wire Protocol (JDWP) |
| * packet declared by the JDWP specification. |
| * |
| */ |
| public abstract class JdwpPacket { |
| /** General JDWP constants. */ |
| public static final byte FLAG_REPLY_PACKET = (byte) 0x80; |
| protected static final int MIN_PACKET_LENGTH = 11; |
| |
| /** Map with Strings for flag bits. */ |
| private static String[] fgFlagStrings = null; |
| |
| /** Header fields. */ |
| protected int fId = 0; |
| protected byte fFlags = 0; |
| protected byte[] fDataBuf = null; |
| |
| /** |
| * Set Id. |
| */ |
| /* package */void setId(int id) { |
| fId = id; |
| } |
| |
| /** |
| * @return Returns Id. |
| */ |
| public int getId() { |
| return fId; |
| } |
| |
| /** |
| * Set Flags. |
| */ |
| /* package */void setFlags(byte flags) { |
| fFlags = flags; |
| } |
| |
| /** |
| * @return Returns Flags. |
| */ |
| public byte getFlags() { |
| return fFlags; |
| } |
| |
| /** |
| * @return Returns total length of packet. |
| */ |
| public int getLength() { |
| return MIN_PACKET_LENGTH + getDataLength(); |
| } |
| |
| /** |
| * @return Returns length of data in packet. |
| */ |
| public int getDataLength() { |
| return fDataBuf == null ? 0 : fDataBuf.length; |
| } |
| |
| /** |
| * @return Returns data of packet. |
| */ |
| public byte[] data() { |
| return fDataBuf; |
| } |
| |
| /** |
| * @return Returns DataInputStream with reply data, or an empty stream if |
| * there is none. |
| */ |
| public DataInputStream dataInStream() { |
| if (fDataBuf != null) { |
| return new DataInputStream(new ByteArrayInputStream(fDataBuf)); |
| } |
| |
| return new DataInputStream(new ByteArrayInputStream(new byte[0])); |
| } |
| |
| /** |
| * Assigns data to packet. |
| */ |
| public void setData(byte[] data) { |
| fDataBuf = data; |
| } |
| |
| /** |
| * Reads header fields that are specific for a type of packet. |
| */ |
| protected abstract int readSpecificHeaderFields(byte[] bytes, int index) |
| throws IOException; |
| |
| /** |
| * Writes header fields that are specific for a type of packet. |
| */ |
| protected abstract int writeSpecificHeaderFields(byte[] bytes, int index) |
| throws IOException; |
| |
| /** |
| * Constructs a JdwpPacket from a byte[]. |
| */ |
| public static JdwpPacket build(byte[] bytes) throws IOException { |
| // length (int) |
| int a = (bytes[0] & 0xff) << 24; |
| int b = (bytes[1] & 0xff) << 16; |
| int c = (bytes[2] & 0xff) << 8; |
| int d = (bytes[3] & 0xff) << 0; |
| int packetLength = a + b + c + d; |
| |
| // id (int) |
| a = (bytes[4] & 0xff) << 24; |
| b = (bytes[5] & 0xff) << 16; |
| c = (bytes[6] & 0xff) << 8; |
| d = (bytes[7] & 0xff) << 0; |
| int id = a + b + c + d; |
| |
| // flags (byte) |
| byte flags = bytes[8]; |
| |
| // Determine type: command or reply. |
| JdwpPacket packet; |
| if ((flags & FLAG_REPLY_PACKET) != 0) |
| packet = new JdwpReplyPacket(); |
| else |
| packet = new JdwpCommandPacket(); |
| |
| // Assign generic header fields. |
| packet.setId(id); |
| packet.setFlags(flags); |
| |
| // Read specific header fields and data. |
| int index = 9; |
| index += packet.readSpecificHeaderFields(bytes, 9); |
| if (packetLength - MIN_PACKET_LENGTH > 0) { |
| packet.fDataBuf = new byte[packetLength - MIN_PACKET_LENGTH]; |
| System.arraycopy(bytes, index, packet.fDataBuf, 0, |
| packet.fDataBuf.length); |
| } |
| |
| return packet; |
| } |
| |
| public byte[] getPacketAsBytes() throws IOException { |
| int len = getLength(); |
| byte[] bytes = new byte[len]; |
| |
| // convert len to bytes |
| bytes[0] = (byte) (len >>> 24); |
| bytes[1] = (byte) (len >>> 16); |
| bytes[2] = (byte) (len >>> 8); |
| bytes[3] = (byte) (len >>> 0); |
| |
| // convert id to bytes |
| int id = getId(); |
| bytes[4] = (byte) (id >>> 24); |
| bytes[5] = (byte) (id >>> 16); |
| bytes[6] = (byte) (id >>> 8); |
| bytes[7] = (byte) (id >>> 0); |
| |
| // flags |
| bytes[8] = getFlags(); |
| |
| // convert specific header fields |
| int index = 9; |
| index += writeSpecificHeaderFields(bytes, index); |
| |
| if (index < len && fDataBuf != null) { |
| // copy data |
| System.arraycopy(fDataBuf, 0, bytes, index, fDataBuf.length); |
| } |
| return bytes; |
| } |
| |
| /** |
| * Retrieves constant mappings. |
| */ |
| public static void getConstantMaps() { |
| if (fgFlagStrings != null) { |
| return; |
| } |
| |
| Field[] fields = JdwpPacket.class.getDeclaredFields(); |
| fgFlagStrings = new String[8]; |
| |
| for (Field field : fields) { |
| if ((field.getModifiers() & Modifier.PUBLIC) == 0 |
| || (field.getModifiers() & Modifier.STATIC) == 0 |
| || (field.getModifiers() & Modifier.FINAL) == 0) { |
| continue; |
| } |
| |
| String name = field.getName(); |
| if (!name.startsWith("FLAG_")) {//$NON-NLS-1$ |
| continue; |
| } |
| |
| name = name.substring(5); |
| |
| try { |
| byte value = field.getByte(null); |
| |
| for (int j = 0; j < fgFlagStrings.length; j++) { |
| if ((1 << j & value) != 0) { |
| fgFlagStrings[j] = name; |
| break; |
| } |
| } |
| } catch (IllegalAccessException e) { |
| // Will not occur for own class. |
| } catch (IllegalArgumentException e) { |
| // Should not occur. |
| // We should take care that all public static final constants |
| // in this class are bytes. |
| } |
| } |
| } |
| |
| /** |
| * @return Returns a mapping with string representations of flags. |
| */ |
| public static String[] getFlagMap() { |
| getConstantMaps(); |
| return fgFlagStrings; |
| } |
| } |