Add more direct encode() and decode() methods.

Also, tweaked a couple messages in CodeReader to match newly-clarified
opcode names, while I was in the territory.

Change-Id: I7bad8be967a3ca9c69f0443d4387b927ccd56d16
diff --git a/dx/src/com/android/dx/io/CodeReader.java b/dx/src/com/android/dx/io/CodeReader.java
index 7ed4a59..a25cb7c 100644
--- a/dx/src/com/android/dx/io/CodeReader.java
+++ b/dx/src/com/android/dx/io/CodeReader.java
@@ -434,7 +434,7 @@
             int offset = (instructions[i + 1] & 0xFFFF)
                     + ((instructions[i + 2] & 0xFFFF) << 16);
             if (instructions[i + offset] != 0x100) {
-                throw new DexException("Expected packed-switch pseudo-opcode but was 0x"
+                throw new DexException("Expected packed-switch-payload opcode but was 0x"
                         + Integer.toHexString(instructions[i + offset]));
             }
             short size = instructions[i + offset + 1];
@@ -450,7 +450,7 @@
             int offset = (instructions[i + 1] & 0xFFFF)
                     + ((instructions[i + 2] & 0xFFFF) << 16);
             if (instructions[i + offset] != 0x200) {
-                throw new DexException("Expected sparse-switch pseudo-opcode but was 0x"
+                throw new DexException("Expected sparse-switch-payload opcode but was 0x"
                         + Integer.toHexString(instructions[i + offset]));
             }
             short size = instructions[i + offset + 1];
@@ -466,7 +466,7 @@
             int offset = (instructions[i + 1] & 0xFFFF)
                     + ((instructions[i + 2] & 0xFFFF) << 16);
             if (instructions[i + offset] != 0x300) {
-                throw new DexException("Expected fill-array-data pseudo-opcode but was 0x"
+                throw new DexException("Expected fill-array-data-payload opcode but was 0x"
                         + Integer.toHexString(instructions[i + offset]));
             }
             int bytesPerElement = instructions[i + offset + 1];
diff --git a/dx/src/com/android/dx/io/DecodedInstruction.java b/dx/src/com/android/dx/io/DecodedInstruction.java
index 23426dd..4e5b337 100644
--- a/dx/src/com/android/dx/io/DecodedInstruction.java
+++ b/dx/src/com/android/dx/io/DecodedInstruction.java
@@ -16,6 +16,8 @@
 
 package com.android.dx.io;
 
+import java.io.EOFException;
+
 /**
  * A decoded Dalvik instruction. This consists of a format codec, a
  * numeric opcode, an optional index type, and any additional
@@ -74,6 +76,17 @@
     private final int e;
 
     /**
+     * Decodes an instruction from the given input source.
+     */
+    public static DecodedInstruction decode(CodeInput in) throws EOFException {
+        int opcodeUnit = in.read();
+        int opcode = Opcodes.extractOpcodeFromUnit(opcodeUnit);
+        InstructionCodec format = OpcodeInfo.getFormat(opcode);
+
+        return format.decode(opcodeUnit, in);
+    }
+
+    /**
      * Constructs an instance. This is the base constructor that takes
      * all arguments.
      */
@@ -232,7 +245,14 @@
     }
 
     /**
-     * Return an instance just like this one, except with the index replaced
+     * Encodes this instance to the given output.
+     */
+    public void encode(CodeOutput out) {
+        format.encode(this, out);
+    }
+
+    /**
+     * Returns an instance just like this one, except with the index replaced
      * with the given one.
      */
     public DecodedInstruction withIndex(int newIndex) {
diff --git a/dx/src/com/android/dx/io/OpcodeInfo.java b/dx/src/com/android/dx/io/OpcodeInfo.java
index 7359dec..133e943 100644
--- a/dx/src/com/android/dx/io/OpcodeInfo.java
+++ b/dx/src/com/android/dx/io/OpcodeInfo.java
@@ -1364,6 +1364,14 @@
     }
 
     /**
+     * Gets the format (an {@link InstructionCodec}) for the given opcode
+     * value.
+     */
+    public static InstructionCodec getFormat(int opcode) {
+        return get(opcode).getFormat();
+    }
+
+    /**
      * Puts the given opcode into the table of all ops.
      *
      * @param opcode non-null; the opcode
diff --git a/dx/src/com/android/dx/io/Opcodes.java b/dx/src/com/android/dx/io/Opcodes.java
index 9dda7a3..51d92c2 100644
--- a/dx/src/com/android/dx/io/Opcodes.java
+++ b/dx/src/com/android/dx/io/Opcodes.java
@@ -334,6 +334,12 @@
      * possibly valid
      */
     public static boolean isValidShape(int opcode) {
+        /*
+         * Note: This method bakes in knowledge that all opcodes are
+         * either single-byte or of the form ((byteValue << 8) |
+         * 0xff).
+         */
+
         // Note: SPECIAL_FORMAT == NO_NEXT.
         if ((opcode >= SPECIAL_FORMAT) && (opcode <= 0xff)) {
             return true;
@@ -346,4 +352,19 @@
 
         return false;
     }
+
+    /**
+     * Gets the opcode out of an opcode unit, the latter of which may also
+     * include one or more argument values.
+     */
+    public static int extractOpcodeFromUnit(int opcodeUnit) {
+        /*
+         * Note: This method bakes in knowledge that all opcodes are
+         * either single-byte or of the form ((byteValue << 8) |
+         * 0xff).
+         */
+
+        int lowByte = opcodeUnit & 0xff;
+        return (lowByte == 0xff) ? opcodeUnit : lowByte;
+    }
 }