I have a slightly more advanced class I am trying to write a toString() for
in order to accomplish what I am trying to do I need to be able to change the assignment of certain variables when doing toString().
TO make it simple I am going to remove a bunch of stuff except what allows it to work.
public enum PacketElementType {
NONE((byte)0, "None"),
BYTE((byte)1, "Byte"),
SHORT((byte)2, "Short"),
INT((byte)3, "Int"),
LONG((byte)4, "Long"),
FLOAT((byte)5, "Float"),
STRING((byte)6, "String"),
BIN((byte)7, "Bin");
private final byte typeValue;
private final String typeName;
PacketElementType(byte type, String name)
{
this.typeValue = type;
this.typeName = name;
}
public String getTypeName() {
return typeName;
}
public byte getTypeValue() {
return typeValue;
}
}
public class Packet {
private final int DEFAULT_SIZE = 1024 * 2;
private final int ADD_SIZE = 1024;
private byte[] _buffer = new byte[1];
private int _ptr = 0;
private int _bodyStart = 0;
private int _elements, _bodyLen = 0;
private int op;
private long id;
public Packet(int op, long id) {
setOp(op);
setId(id);
_buffer = new byte[DEFAULT_SIZE];
}
public int getOp() {
return op;
}
public void setOp(int op) {
this.op = op;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public PacketElementType peek() {
int pie = _ptr;
if (pie + 2 > _buffer.length)
return PacketElementType.NONE;
return PacketElementType.values()[_buffer[_ptr]];
}
protected Packet putSimple(PacketElementType type, byte... val) {
int len = val.length + 1;
this.ensureSize(len);
_buffer[++_ptr] = type.getTypeValue();
System.arraycopy(val, 0, _buffer, _ptr, val.length);
_ptr += val.length;
_elements++;
_bodyLen += len;
return this;
}
public Packet putByte(byte val) {
return this.putSimple(PacketElementType.BYTE, val);
}
public Packet putByte(boolean val) {
return this.putByte(val ? (byte) 1 : (byte) 0);
}
public byte getByte() throws Exception {
if (this.peek() != PacketElementType.BYTE)
throw new Exception("Expected Byte, got " + this.peek().getTypeName() + ".");
_ptr += 1;
return _buffer[++_ptr];
}
protected void ensureSize(int required) {
if (_ptr + required >= _buffer.length) {
byte[] b = new byte[_buffer.length + Math.max(ADD_SIZE, required * 2)];
System.arraycopy(_buffer, 0, b, 0, _buffer.length);
_buffer = b;
}
}
private boolean isValidType(PacketElementType type)
{
return (type.getTypeValue() >= PacketElementType.BYTE.getTypeValue() && type.getTypeValue() <= PacketElementType.BIN.getTypeValue());
}
protected String toStringHack()
{
StringBuilder result = new StringBuilder();
int prevPtu = _ptr;
_ptr = _bodyStart;
try {
result.append(String.format("Op: %1$08d %3$s, Id: %2$016d\r\n", this.getOp(), this.getId(), Op.getName(this.getOp())));
} catch (IllegalAccessException e) {
e.printStackTrace();
return result.append("Failed to convert packet to string").toString();
}
PacketElementType type;
for (int i = 1; (this.isValidType(type = this.peek()) && _ptr < _buffer.length); ++i)
{
if (type == PacketElementType.BYTE)
{
byte data = 0;
try {
data = getByte();
} catch (Exception e) {
e.printStackTrace();
result.append("Failed to parse element at position ").append(i);
continue;
}
result.append(String.format("%1&03d [%2$s] Byte : %3$s", i, String.format("%1$016d", data), data));
}
}
return result.toString();
}
//TODO: toString
@Override
public String toString()
{
return toStringHack();
}
}
public class Op {
public class Msgr
{
}
public static String getName(int op) throws IllegalAccessException {
for (Field field : Op.class.getFields())
{
if ((int)field.get(null) == op)
return field.getName();
}
for (Field field : Op.Msgr.class.getFields())
{
if ((int)field.get(null) == op)
return field.getName();
}
return "?";
}
}
[
2
When debugging, _ptr won't set in toString(), when not debugging, _ptr won't set in putSimple().
I'm so close to pulling my hair out, please and thanks, if you could help me I would really be glad! Please and thank you again!
To test for this bug please review the following example:
Packet p = new Packet(1, 10001).putByte(true);
Toast.makeText(this, p.toString(), Toast.LENGTH_LONG).show();
for me I throw this inside the built in test class first, and then tried it in the onCreate from the main activity.
toString() will only return the Op and Id because _ptr is at , peek() will attempt to read the byte starting at that position instead of at 0 where it would find our 1 byte.
It seems like... _ptr = _bodyStart; is being seen as something other than an assignment, is this possible?
Result you see is ok - debugger shows you those variables before evaluation. Ad a line after this one (like a log or smth.) and set breakpoint on it.
so it turns out I was missing just one small tiny little details..... Not tiny at all, I apologize for not seeing this earlier. toString() would fail because of a malformed String.format() call as well as the failure to set ptr back to it's original value after toString() was completed.
result.append(String.format("%1&03d [%2$s] Byte : %3$s", i, String.format("%1$016d", data), data));
Should have been (where right after %1 I had an & instead of a $)
String hello = String.format("%1$03d [%2$s] Byte : %3$d\r\n", i, StringUtils.leftPad(String.format("%02X", data), 16, '.'), (int) data);
and just before returning the string, I needed to do the following
ptr = prevPtu;
with that, the following happens:

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With