/*
*
*
* Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.cldchi.tools.memoryprofiler.jdwp;
import java.util.Vector;
/**
* This class encapsulates JDWP packet. It based on
* <code>ByteBuffer</code> but adds methods for working with data
* specific for JDWP packet. This class is not used directly, its subclasses
* <code>Command</code> and <code>Reply</code> are used instead. For
* information about JDWP packet see JDWP specification.
*
* @see jdwp.ByteBuffer
* @see jdwp.Command
* @see jdwp.Reply
*/
class Packet extends ByteBuffer {
/**
* JDWP packet flag "no flags". Indicates that the packet is a command.
*/
public final static int flNoFlags = 0x0;
/**
* JDWP packet flag <code>Reply</code>. Indicates that the packet is a
* reply.
*/
public final static int flReply = 0x80;
/**
* Offset of the "packet length" field in the JDWP packet.
*/
public final static int LengthOffset = 0;
/**
* Offset of the "packet ID" field in the JDWP packet.
*/
public final static int IdOffset = 4;
/**
* Offset of the "flags" field in the JDWP packet.
*/
public final static int FlagsOffset = 8;
/**
* Offset of the "command number" field in the JDWP packet.
*/
public final static int CommandOffset = 9;
/**
* Offset of the "error code" field in the JDWP packet.
*/
public final static int ErrorCodeOffset = 9;
/**
* Size of JDWP packet's header.
*/
public final static int PacketHeaderSize = 11;
/**
* Create a new JDWP packet fills its header by zeros.
*/
public Packet() {
super();
while (length() < PacketHeaderSize){
addByte(0);
}
}
/**
* Sets "packet length" field of the JDWP packet
*/
public void setLength() {
try {
putInt(LengthOffset, length());
}
catch (BoundException e) {};
}
/**
* Returns ID of the JDWP packet.
*
* @return ID of the JDWP packet
*/
public int getID() {
int id = 0;
try {
id = getInt(IdOffset);
}
catch (BoundException e) {};
return id;
}
/**
* Sets ID of the JDWP packet.
*
* @param Id ID of the JDWP packet
*/
public void setID(int Id) {
try {
putInt(IdOffset, Id);
}
catch (BoundException e) {};
}
/**
* Returns flags of the JDWP packet.
*
* @return flags of the JDWP packet.
*/
public int getFlags() {
return bytes[FlagsOffset] & 0xff;
}
/**
* Sets flags of the JDWP packet.
*
* @param Flags flags to be set
*/
public void setFlags(int Flags) {
bytes[FlagsOffset] = (byte) (Flags & 0xFF);
}
/**
* Moves the reading marker to the beginning of packet data
* (after the header). To learn about reading marker see
* <code>ByteBuffer</code>.
*
* @see jdwp.ByteBuffer
*/
public void resetDataParser() {
resetParser(PacketHeaderSize);
}
/**
* Returns size of packet's data (i.e., size of the packet
* excluding header).
*
* @return size of packet's data
*/
public int getDataSize() {
return length() - PacketHeaderSize;
}
/**
* Adds a field ID to the end of JDWP packet.
*
* @param b ID to be added
*/
public void addFieldID(long b) {
addID(b, jdwp.fieldIDSize);
}
/**
* Adds a method ID to the end of JDWP packet.
*
* @param b ID to be added
*/
public void addMethodID(long b) {
addID(b, jdwp.methodIDSize);
}
/**
* Adds an object ID to the end of JDWP packet.
*
* @param b ID to be added
*/
public void addObjectID(long b) {
addID(b, jdwp.objectIDSize);
}
/**
* Adds a reference type ID to the end of JDWP packet.
*
* @param b ID to be added
*/
public void addReferenceTypeID(long b) {
addID(b, jdwp.referenceTypeIDSize);
}
/**
* Adds a frame ID to the end of JDWP packet.
*
* @param b ID to be added
*/
public void addFrameID(long b) {
addID(b, jdwp.frameIDSize);
}
/**
* Tries to read next field ID from the buffer.
* Value is read is one
* that is pointed by reading marker. After completing the operation
* the reading marker is incremented.
*
* @return current field ID from the buffer
* @throws BoundException if value to be read is outside the filled area
*/
public long getFieldID() throws BoundException {
return getID(jdwp.fieldIDSize);
}
/**
* Tries to read next method ID from the buffer.
* Value is read is one
* that is pointed by reading marker. After completing the operation
* the reading marker is incremented.
*
* @return current method ID from the buffer
* @throws BoundException if value to be read is outside the filled area
*/
public long getMethodID() throws BoundException {
return getID(jdwp.methodIDSize);
}
/**
* Tries to read next object ID from the buffer.
* Value is read is one
* that is pointed by reading marker. After completing the operation
* the reading marker is incremented.
*
* @return current object ID from the buffer
* @throws BoundException if value to be read is outside the filled area
*/
public long getObjectID() throws BoundException {
return getID(jdwp.objectIDSize);
}
/**
* Tries to read next reference type ID from the buffer.
* Value is read is one
* that is pointed by reading marker. After completing the operation
* the reading marker is incremented.
*
* @return current reference type ID from the buffer
* @throws BoundException if value to be read is outside the filled area
*/
public long getReferenceTypeID() throws BoundException {
return getID(jdwp.referenceTypeIDSize);
}
/**
* Tries to read next frame ID from the buffer.
* Value is read is one
* that is pointed by reading marker. After completing the operation
* the reading marker is incremented.
*
* @return current frame ID from the buffer
* @throws BoundException if value to be read is outside the filled area
*/
public long getFrameID() throws BoundException {
return getID(jdwp.frameIDSize);
}
/**
* Parses the JDWP packet according to the specified mask. The mask
* specifies what elements are contained in JDWP packet's data. The rules
* are as follows:
* <ul>
* <li> b - a byte value
* <li> i - an int value
* <li> S - a short value
* <li> l - a long value
* <li> s - a string value
* <li> f - a field ID
* <li> m - a method ID
* <li> o - an object ID
* <li> r - a reference type ID
* <li> F - a frame ID
* <li> v - a value. The first byte indicates type tag of the
* variable, the second is a variable's value.
* <li> . - a set of data in the end of packet that should not be parsed.
* <li> i(<submask>) - the first integer indicates how many times
* submask is appeared in the packet.
* </ul>
* For example, the mask <code>li(rm)</code> means that the first element
* of packet's data is a <code>long</code> value, then an <code>int</code>
* value that indicates how many times the pair "reference type ID -
* method ID" is appeared later.
*
* @param how a mask that indicates how to parse a packet.
* @return a vector of parsed elements of the packet's data. The classes
* that represent different types of elements are written below:
* <ul>
* <li> b - <code>java.lang.Integer</code>
* <li> i - <code>java.lang.Integer</code>
* <li> S - <code>java.lang.Integer</code>
* <li> l - <code>java.lang.Long</code>
* <li> s - <code>java.lang.String</code>
* <li> f - <code>java.lang.Long</code>
* <li> m - <code>java.lang.Long</code>
* <li> o - <code>java.lang.Long</code>
* <li> r - <code>java.lang.Long</code>
* <li> F - <code>java.lang.Long</code>
* <li> v - The tag of the value is represented by
* <code>java.lang.Integer</code>. The value itself is represented
* according to this table
* </ul>
*/
public Vector parse(String how) throws BoundException {
boolean check;
check = (how.indexOf('.') == -1);
if (! check) {
if (how.indexOf('.') != how.length() - 1)
throw new BoundException();
how = Tools.Left(how, how.length() - 1);
}
Vector v = new Vector();
resetDataParser();
doParse(how, v);
if (check && (! isParsed()))
throw new BoundException();
return v;
}
/**
* Performs the parsing of the JDWP oacket in fact. The all the
* parsing rules that described in the description of
* <code>parse</code> method are the same besides of absence of
* '.' symbol in the mask.
*
* @param how a mask that describes types of elements
* @param v a vector for keeping results
*
* @see #parse(java.lang.String)
*/
private void doParse(String how, Vector v) throws BoundException {
int index = 0;
char[] h = how.toCharArray();
while (index < h.length) {
switch (h[index]) {
case 'b':
v.add(new Integer(getByte()));
break;
case 'i':
v.add(new Integer(getInt()));
break;
case 'S':
v.add(new Integer(getShort()));
break;
case 'l':
v.add(new Long(getLong()));
break;
case 's':
v.add(getString());
break;
case 'f':
v.add(new Long(getFieldID()));
break;
case 'm':
v.add(new Long(getMethodID()));
break;
case 'o':
v.add(new Long(getObjectID()));
break;
case 'r':
v.add(new Long(getReferenceTypeID()));
break;
case 'F':
v.add(new Long(getFrameID()));
break;
case 'v':
int vtype = getByte();
v.add(new Integer(vtype));
switch (vtype) {
case jdwp.tagARRAY:
case jdwp.tagOBJECT:
v.add(new Long(getObjectID()));
break;
case jdwp.tagBYTE:
v.add(new Integer(getByte()));
break;
case jdwp.tagINT:
v.add(new Integer(getInt()));
break;
case jdwp.tagSHORT:
v.add(new Integer(getShort()));
break;
case jdwp.tagVOID:
v.add("void value");
break;
case jdwp.tagBOOLEAN:
v.add(new Integer(getByte()));
break;
case jdwp.tagLONG:
v.add(new Long(getLong()));
break;
default:
throw new BoundException();
}
break;
case '(':
if (index == 0)
throw new BoundException();
if (h[index - 1] != 'i')
throw new BoundException();
int n = ((Integer) v.elementAt(v.size() - 1)).intValue();
if (n < 0)
throw new BoundException();
int pos = index + 1;
int cnt = 1;
int last = -1;
while (pos < h.length) {
if (h[pos] == '(')
cnt++;
if (h[pos] == ')') {
cnt--;
if (cnt == 0) {
last = pos;
break;
}
}
pos++;
}
if (last == -1)
throw new BoundException();
String s = new String(h, index + 1, last - index - 1);
for (int i = 0; i < n; i++)
doParse(s, v);
index = last;
break;
default:
throw new BoundException();
}
index++;
}
}
}
|