1 package com.android.test.hierarchyviewer; 2 3 import java.nio.ByteBuffer; 4 import java.nio.charset.Charset; 5 import java.util.HashMap; 6 import java.util.Map; 7 8 public class Decoder { 9 // Prefixes for simple primitives. These match the JNI definitions. 10 public static final byte SIG_BOOLEAN = 'Z'; 11 public static final byte SIG_BYTE = 'B'; 12 public static final byte SIG_SHORT = 'S'; 13 public static final byte SIG_INT = 'I'; 14 public static final byte SIG_LONG = 'J'; 15 public static final byte SIG_FLOAT = 'F'; 16 public static final byte SIG_DOUBLE = 'D'; 17 18 // Prefixes for some commonly used objects 19 public static final byte SIG_STRING = 'R'; 20 21 public static final byte SIG_MAP = 'M'; // a map with an short key 22 public static final short SIG_END_MAP = 0; 23 24 private final ByteBuffer mBuf; 25 Decoder(byte[] buf)26 public Decoder(byte[] buf) { 27 this(ByteBuffer.wrap(buf)); 28 } 29 Decoder(ByteBuffer buf)30 public Decoder(ByteBuffer buf) { 31 mBuf = buf; 32 } 33 hasRemaining()34 public boolean hasRemaining() { 35 return mBuf.hasRemaining(); 36 } 37 readObject()38 public Object readObject() { 39 byte sig = mBuf.get(); 40 41 switch (sig) { 42 case SIG_BOOLEAN: 43 return mBuf.get() == 0 ? Boolean.FALSE : Boolean.TRUE; 44 case SIG_BYTE: 45 return mBuf.get(); 46 case SIG_SHORT: 47 return mBuf.getShort(); 48 case SIG_INT: 49 return mBuf.getInt(); 50 case SIG_LONG: 51 return mBuf.getLong(); 52 case SIG_FLOAT: 53 return mBuf.getFloat(); 54 case SIG_DOUBLE: 55 return mBuf.getDouble(); 56 case SIG_STRING: 57 return readString(); 58 case SIG_MAP: 59 return readMap(); 60 default: 61 throw new DecoderException(sig, mBuf.position() - 1); 62 } 63 } 64 readString()65 private String readString() { 66 short len = mBuf.getShort(); 67 byte[] b = new byte[len]; 68 mBuf.get(b, 0, len); 69 return new String(b, Charset.forName("utf-8")); 70 } 71 readMap()72 private Map<Short, Object> readMap() { 73 Map<Short, Object> m = new HashMap<Short, Object>(); 74 75 while (true) { 76 Object o = readObject(); 77 if (!(o instanceof Short)) { 78 throw new DecoderException("Expected short key, got " + o.getClass()); 79 } 80 81 Short key = (Short)o; 82 if (key == SIG_END_MAP) { 83 break; 84 } 85 86 m.put(key, readObject()); 87 } 88 89 return m; 90 } 91 92 public static class DecoderException extends RuntimeException { DecoderException(byte seen, int pos)93 public DecoderException(byte seen, int pos) { 94 super(String.format("Unexpected byte %c seen at position %d", (char)seen, pos)); 95 } 96 DecoderException(String msg)97 public DecoderException(String msg) { 98 super(msg); 99 } 100 } 101 } 102