package com.android.test.hierarchyviewer; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.HashMap; import java.util.Map; public class Decoder { // Prefixes for simple primitives. These match the JNI definitions. public static final byte SIG_BOOLEAN = 'Z'; public static final byte SIG_BYTE = 'B'; public static final byte SIG_SHORT = 'S'; public static final byte SIG_INT = 'I'; public static final byte SIG_LONG = 'J'; public static final byte SIG_FLOAT = 'F'; public static final byte SIG_DOUBLE = 'D'; // Prefixes for some commonly used objects public static final byte SIG_STRING = 'R'; public static final byte SIG_MAP = 'M'; // a map with an short key public static final short SIG_END_MAP = 0; private final ByteBuffer mBuf; public Decoder(byte[] buf) { this(ByteBuffer.wrap(buf)); } public Decoder(ByteBuffer buf) { mBuf = buf; } public boolean hasRemaining() { return mBuf.hasRemaining(); } public Object readObject() { byte sig = mBuf.get(); switch (sig) { case SIG_BOOLEAN: return mBuf.get() == 0 ? Boolean.FALSE : Boolean.TRUE; case SIG_BYTE: return mBuf.get(); case SIG_SHORT: return mBuf.getShort(); case SIG_INT: return mBuf.getInt(); case SIG_LONG: return mBuf.getLong(); case SIG_FLOAT: return mBuf.getFloat(); case SIG_DOUBLE: return mBuf.getDouble(); case SIG_STRING: return readString(); case SIG_MAP: return readMap(); default: throw new DecoderException(sig, mBuf.position() - 1); } } private String readString() { short len = mBuf.getShort(); byte[] b = new byte[len]; mBuf.get(b, 0, len); return new String(b, Charset.forName("utf-8")); } private Map readMap() { Map m = new HashMap(); while (true) { Object o = readObject(); if (!(o instanceof Short)) { throw new DecoderException("Expected short key, got " + o.getClass()); } Short key = (Short)o; if (key == SIG_END_MAP) { break; } m.put(key, readObject()); } return m; } public static class DecoderException extends RuntimeException { public DecoderException(byte seen, int pos) { super(String.format("Unexpected byte %c seen at position %d", (char)seen, pos)); } public DecoderException(String msg) { super(msg); } } }