001: /*******************************************************************************
002: * Copyright (c) 2000, 2005 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdi.internal.jdwp;
011:
012: import java.io.ByteArrayInputStream;
013: import java.io.DataInputStream;
014: import java.io.IOException;
015: import java.lang.reflect.Field;
016: import java.lang.reflect.Modifier;
017:
018: /**
019: * This class implements the corresponding Java Debug Wire Protocol (JDWP) packet
020: * declared by the JDWP specification.
021: *
022: */
023: public abstract class JdwpPacket {
024: /** General JDWP constants. */
025: public static final byte FLAG_REPLY_PACKET = (byte) 0x80;
026: protected static final int MIN_PACKET_LENGTH = 11;
027:
028: /** Map with Strings for flag bits. */
029: private static String[] fgFlagStrings = null;
030:
031: /** Header fields. */
032: protected int fId = 0;
033: protected byte fFlags = 0;
034: protected byte[] fDataBuf = null;
035:
036: /**
037: * Set Id.
038: */
039: /*package*/void setId(int id) {
040: fId = id;
041: }
042:
043: /**
044: * @return Returns Id.
045: */
046: public int getId() {
047: return fId;
048: }
049:
050: /**
051: * Set Flags.
052: */
053: /*package*/void setFlags(byte flags) {
054: fFlags = flags;
055: }
056:
057: /**
058: * @return Returns Flags.
059: */
060: public byte getFlags() {
061: return fFlags;
062: }
063:
064: /**
065: * @return Returns total length of packet.
066: */
067: public int getLength() {
068: return MIN_PACKET_LENGTH + getDataLength();
069: }
070:
071: /**
072: * @return Returns length of data in packet.
073: */
074: public int getDataLength() {
075: return fDataBuf == null ? 0 : fDataBuf.length;
076: }
077:
078: /**
079: * @return Returns data of packet.
080: */
081: public byte[] data() {
082: return fDataBuf;
083: }
084:
085: /**
086: * @return Returns DataInputStream with reply data, or an empty stream if there is none.
087: */
088: public DataInputStream dataInStream() {
089: if (fDataBuf != null) {
090: return new DataInputStream(new ByteArrayInputStream(
091: fDataBuf));
092: }
093:
094: return new DataInputStream(
095: new ByteArrayInputStream(new byte[0]));
096: }
097:
098: /**
099: * Assigns data to packet.
100: */
101: public void setData(byte[] data) {
102: fDataBuf = data;
103: }
104:
105: /**
106: * Reads header fields that are specific for a type of packet.
107: */
108: protected abstract int readSpecificHeaderFields(byte[] bytes,
109: int index) throws IOException;
110:
111: /**
112: * Writes header fields that are specific for a type of packet.
113: */
114: protected abstract int writeSpecificHeaderFields(byte[] bytes,
115: int index) throws IOException;
116:
117: /**
118: * Constructs a JdwpPacket from a byte[].
119: */
120: public static JdwpPacket build(byte[] bytes) throws IOException {
121: // length (int)
122: int a = (bytes[0] & 0xff) << 24;
123: int b = (bytes[1] & 0xff) << 16;
124: int c = (bytes[2] & 0xff) << 8;
125: int d = (bytes[3] & 0xff) << 0;
126: int packetLength = a + b + c + d;
127:
128: // id (int)
129: a = (bytes[4] & 0xff) << 24;
130: b = (bytes[5] & 0xff) << 16;
131: c = (bytes[6] & 0xff) << 8;
132: d = (bytes[7] & 0xff) << 0;
133: int id = a + b + c + d;
134:
135: // flags (byte)
136: byte flags = bytes[8];
137:
138: // Determine type: command or reply.
139: JdwpPacket packet;
140: if ((flags & FLAG_REPLY_PACKET) != 0)
141: packet = new JdwpReplyPacket();
142: else
143: packet = new JdwpCommandPacket();
144:
145: // Assign generic header fields.
146: packet.setId(id);
147: packet.setFlags(flags);
148:
149: // Read specific header fields and data.
150: int index = 9;
151: index += packet.readSpecificHeaderFields(bytes, 9);
152: if (packetLength - MIN_PACKET_LENGTH > 0) {
153: packet.fDataBuf = new byte[packetLength - MIN_PACKET_LENGTH];
154: System.arraycopy(bytes, index, packet.fDataBuf, 0,
155: packet.fDataBuf.length);
156: }
157:
158: return packet;
159: }
160:
161: public byte[] getPacketAsBytes() throws IOException {
162: int len = getLength();
163: byte[] bytes = new byte[len];
164:
165: //convert len to bytes
166: bytes[0] = (byte) (len >>> 24);
167: bytes[1] = (byte) (len >>> 16);
168: bytes[2] = (byte) (len >>> 8);
169: bytes[3] = (byte) (len >>> 0);
170:
171: //convert id to bytes
172: int id = getId();
173: bytes[4] = (byte) (id >>> 24);
174: bytes[5] = (byte) (id >>> 16);
175: bytes[6] = (byte) (id >>> 8);
176: bytes[7] = (byte) (id >>> 0);
177:
178: //flags
179: bytes[8] = getFlags();
180:
181: //convert specific header fields
182: int index = 9;
183: index += writeSpecificHeaderFields(bytes, index);
184:
185: if (index < len && fDataBuf != null) {
186: //copy data
187: System
188: .arraycopy(fDataBuf, 0, bytes, index,
189: fDataBuf.length);
190: }
191: return bytes;
192: }
193:
194: /**
195: * Retrieves constant mappings.
196: */
197: public static void getConstantMaps() {
198: if (fgFlagStrings != null) {
199: return;
200: }
201:
202: Field[] fields = JdwpPacket.class.getDeclaredFields();
203: fgFlagStrings = new String[8];
204:
205: for (int i = 0; i < fields.length; i++) {
206: Field field = fields[i];
207: if ((field.getModifiers() & Modifier.PUBLIC) == 0
208: || (field.getModifiers() & Modifier.STATIC) == 0
209: || (field.getModifiers() & Modifier.FINAL) == 0) {
210: continue;
211: }
212:
213: String name = field.getName();
214: if (!name.startsWith("FLAG_")) {//$NON-NLS-1$
215: continue;
216: }
217:
218: name = name.substring(5);
219:
220: try {
221: byte value = field.getByte(null);
222:
223: for (int j = 0; j < fgFlagStrings.length; j++) {
224: if ((1 << j & value) != 0) {
225: fgFlagStrings[j] = name;
226: break;
227: }
228: }
229: } catch (IllegalAccessException e) {
230: // Will not occur for own class.
231: } catch (IllegalArgumentException e) {
232: // Should not occur.
233: // We should take care that all public static final constants
234: // in this class are bytes.
235: }
236: }
237: }
238:
239: /**
240: * @return Returns a mapping with string representations of flags.
241: */
242: public static String[] getFlagMap() {
243: getConstantMaps();
244: return fgFlagStrings;
245: }
246: }
|