Home | History | Annotate | Download | only in hierarchyviewer
      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 
     26     public Decoder(byte[] buf) {
     27         this(ByteBuffer.wrap(buf));
     28     }
     29 
     30     public Decoder(ByteBuffer buf) {
     31         mBuf = buf;
     32     }
     33 
     34     public boolean hasRemaining() {
     35         return mBuf.hasRemaining();
     36     }
     37 
     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 
     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 
     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 {
     93         public DecoderException(byte seen, int pos) {
     94             super(String.format("Unexpected byte %c seen at position %d", (char)seen, pos));
     95         }
     96 
     97         public DecoderException(String msg) {
     98             super(msg);
     99         }
    100     }
    101 }
    102