Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Issue with toString() Implementation in Android

Tags:

java

android

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 "?";
    }
}

debug view close [debug view far (after some instructions)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.

Edit

It seems like... _ptr = _bodyStart; is being seen as something other than an assignment, is this possible?

like image 879
ImaBrokeDude Avatar asked Mar 11 '26 04:03

ImaBrokeDude


2 Answers

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.

like image 136
piotrpo Avatar answered Mar 13 '26 16:03

piotrpo


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:

COrrectly Working picture :D

like image 26
ImaBrokeDude Avatar answered Mar 13 '26 17:03

ImaBrokeDude