FileDocCategorySizeDatePackage
ValueEncoder.javaAPI DocAndroid 1.5 API18301Wed May 06 22:41:02 BST 2009com.android.dx.dex.file

ValueEncoder

public final class ValueEncoder extends Object
Handler for writing out encoded_values and parts thereof.

Fields Summary
private static final int
VALUE_BYTE
annotation value type constant: byte
private static final int
VALUE_SHORT
annotation value type constant: short
private static final int
VALUE_CHAR
annotation value type constant: char
private static final int
VALUE_INT
annotation value type constant: int
private static final int
VALUE_LONG
annotation value type constant: long
private static final int
VALUE_FLOAT
annotation value type constant: float
private static final int
VALUE_DOUBLE
annotation value type constant: double
private static final int
VALUE_STRING
annotation value type constant: string
private static final int
VALUE_TYPE
annotation value type constant: type
private static final int
VALUE_FIELD
annotation value type constant: field
private static final int
VALUE_METHOD
annotation value type constant: method
private static final int
VALUE_ENUM
annotation value type constant: enum
private static final int
VALUE_ARRAY
annotation value type constant: array
private static final int
VALUE_ANNOTATION
annotation value type constant: annotation
private static final int
VALUE_NULL
annotation value type constant: null
private static final int
VALUE_BOOLEAN
annotation value type constant: boolean
private final DexFile
file
non-null; file being written
private final com.android.dx.util.AnnotatedOutput
out
non-null; output stream to write to
Constructors Summary
public ValueEncoder(DexFile file, com.android.dx.util.AnnotatedOutput out)
Construct an instance.

param
file non-null; file being written
param
out non-null; output stream to write to

    
                           
         
        if (file == null) {
            throw new NullPointerException("file == null");
        }

        if (out == null) {
            throw new NullPointerException("out == null");
        }

        this.file = file;
        this.out = out;
    
Methods Summary
public static voidaddContents(DexFile file, com.android.dx.rop.annotation.Annotation annotation)
Helper for addContents() methods, which adds contents for a particular {@link Annotation}, calling itself recursively should it encounter a nested annotation.

param
file non-null; the file to add to
param
annotation non-null; the annotation to add contents for

        TypeIdsSection typeIds = file.getTypeIds();
        StringIdsSection stringIds = file.getStringIds();

        typeIds.intern(annotation.getType());
        
        for (NameValuePair pair : annotation.getNameValuePairs()) {
            stringIds.intern(pair.getName());
            addContents(file, pair.getValue());
        }
    
public static voidaddContents(DexFile file, com.android.dx.rop.cst.Constant cst)
Helper for addContents() methods, which adds contents for a particular constant, calling itself recursively should it encounter a {@link CstArray} and calling {@link #addContents(DexFile,Annotation)} recursively should it encounter a {@link CstAnnotation}.

param
file non-null; the file to add to
param
cst non-null; the constant to add contents for

        TypeIdsSection typeIds = file.getTypeIds();
        StringIdsSection stringIds = file.getStringIds();

        if (cst instanceof CstAnnotation) {
            addContents(file, ((CstAnnotation) cst).getAnnotation());
        } else if (cst instanceof CstArray) {
            CstArray.List list = ((CstArray) cst).getList();
            int size = list.size();
            for (int i = 0; i < size; i++) {
                addContents(file, list.get(i));
            }
        } else {
            file.internIfAppropriate(cst);
        }
    
public static java.lang.StringconstantToHuman(com.android.dx.rop.cst.Constant cst)
Gets the colloquial type name and human form of the type of the given constant, when used as an encoded value.

param
cst non-null; the constant
return
non-null; its type name and human form

        int type = constantToValueType(cst);

        if (type == VALUE_NULL) {
            return "null";
        }

        StringBuilder sb = new StringBuilder();

        sb.append(cst.typeName());
        sb.append(' ");
        sb.append(cst.toHuman());

        return sb.toString();
    
private static intconstantToValueType(com.android.dx.rop.cst.Constant cst)
Gets the value type for the given constant.

param
cst non-null; the constant
return
the value type; one of the VALUE_* constants defined by this class

        /*
         * TODO: Constant should probable have an associated enum, so this
         * can be a switch().
         */
        if (cst instanceof CstByte) {
            return VALUE_BYTE;
        } else if (cst instanceof CstShort) {
            return VALUE_SHORT;
        } else if (cst instanceof CstChar) {
            return VALUE_CHAR;
        } else if (cst instanceof CstInteger) {
            return VALUE_INT;
        } else if (cst instanceof CstLong) {
            return VALUE_LONG;
        } else if (cst instanceof CstFloat) {
            return VALUE_FLOAT;
        } else if (cst instanceof CstDouble) {
            return VALUE_DOUBLE;
        } else if (cst instanceof CstString) {
            return VALUE_STRING;
        } else if (cst instanceof CstType) {
            return VALUE_TYPE;
        } else if (cst instanceof CstFieldRef) {
            return VALUE_FIELD;
        } else if (cst instanceof CstMethodRef) {
            return VALUE_METHOD;
        } else if (cst instanceof CstEnumRef) {
            return VALUE_ENUM;
        } else if (cst instanceof CstArray) {
            return VALUE_ARRAY;
        } else if (cst instanceof CstAnnotation) {
            return VALUE_ANNOTATION;
        } else if (cst instanceof CstKnownNull) {
            return VALUE_NULL;
        } else if (cst instanceof CstBoolean) {
            return VALUE_BOOLEAN;
        } else {
            throw new RuntimeException("Shouldn't happen");
        }
    
public voidwriteAnnotation(com.android.dx.rop.annotation.Annotation annotation, boolean topLevel)
Writes out the encoded form of the given annotation, that is, as an encoded_annotation and not including a value_type prefix. If the output stream keeps (debugging) annotations and topLevel is true, then this method will write (debugging) annotations.

param
annotation non-null; annotation instance to write
param
topLevel true iff the given annotation is the top-level annotation or false if it is a sub-annotation of some other annotation

        boolean annotates = topLevel && out.annotates();
        StringIdsSection stringIds = file.getStringIds();
        TypeIdsSection typeIds = file.getTypeIds();

        CstType type = annotation.getType();
        int typeIdx = typeIds.indexOf(type);

        if (annotates) {
            out.annotate("  type_idx: " + Hex.u4(typeIdx) + " // " +
                    type.toHuman());
        }
                    
        out.writeUnsignedLeb128(typeIds.indexOf(annotation.getType()));

        Collection<NameValuePair> pairs = annotation.getNameValuePairs();
        int size = pairs.size();

        if (annotates) {
            out.annotate("  size: " + Hex.u4(size));
        }

        out.writeUnsignedLeb128(size);

        int at = 0;
        for (NameValuePair pair : pairs) {
            CstUtf8 name = pair.getName();
            int nameIdx = stringIds.indexOf(name);
            Constant value = pair.getValue();
            
            if (annotates) {
                out.annotate(0, "  elements[" + at + "]:");
                at++;
                out.annotate("    name_idx: " + Hex.u4(nameIdx) + " // " +
                        name.toHuman());
            }

            out.writeUnsignedLeb128(nameIdx);

            if (annotates) {
                out.annotate("    value: " + constantToHuman(value));
            }

            writeConstant(value);
        }

        if (annotates) {
            out.endAnnotation();
        }
    
public voidwriteArray(com.android.dx.rop.cst.CstArray array, boolean topLevel)
Writes out the encoded form of the given array, that is, as an encoded_array and not including a value_type prefix. If the output stream keeps (debugging) annotations and topLevel is true, then this method will write (debugging) annotations.

param
array non-null; array instance to write
param
topLevel true iff the given annotation is the top-level annotation or false if it is a sub-annotation of some other annotation

        boolean annotates = topLevel && out.annotates();
        CstArray.List list = ((CstArray) array).getList();
        int size = list.size();

        if (annotates) {
            out.annotate("  size: " + Hex.u4(size));
        }
        
        out.writeUnsignedLeb128(size);

        for (int i = 0; i < size; i++) {
            Constant cst = list.get(i);
            if (annotates) {
                out.annotate("  [" + Integer.toHexString(i) + "] " +
                        constantToHuman(cst));
            }
            writeConstant(cst);
        }

        if (annotates) {
            out.endAnnotation();
        }
    
public voidwriteConstant(com.android.dx.rop.cst.Constant cst)
Writes out the encoded form of the given constant.

param
cst non-null; the constant to write

        int type = constantToValueType(cst);
        int arg;

        switch (type) {
            case VALUE_BYTE:
            case VALUE_SHORT:
            case VALUE_INT:
            case VALUE_LONG: {
                long value = ((CstLiteralBits) cst).getLongBits();
                writeSignedIntegralValue(type, value);
                break;
            }
            case VALUE_CHAR: {
                long value = ((CstLiteralBits) cst).getLongBits();
                writeUnsignedIntegralValue(type, value);
                break;
            }
            case VALUE_FLOAT: {
                // Shift value left 32 so that right-zero-extension works.
                long value = ((CstFloat) cst).getLongBits() << 32;
                writeRightZeroExtendedValue(type, value);
                break;
            }
            case VALUE_DOUBLE: {
                long value = ((CstDouble) cst).getLongBits();
                writeRightZeroExtendedValue(type, value);
                break;
            }
            case VALUE_STRING: {
                int index = file.getStringIds().indexOf((CstString) cst);
                writeUnsignedIntegralValue(type, (long) index);
                break;
            }
            case VALUE_TYPE: {
                int index = file.getTypeIds().indexOf((CstType) cst);
                writeUnsignedIntegralValue(type, (long) index);
                break;
            }
            case VALUE_FIELD: {
                int index = file.getFieldIds().indexOf((CstFieldRef) cst);
                writeUnsignedIntegralValue(type, (long) index);
                break;
            }
            case VALUE_METHOD: {
                int index = file.getMethodIds().indexOf((CstMethodRef) cst);
                writeUnsignedIntegralValue(type, (long) index);
                break;
            }
            case VALUE_ENUM: {
                CstFieldRef fieldRef = ((CstEnumRef) cst).getFieldRef();
                int index = file.getFieldIds().indexOf(fieldRef);
                writeUnsignedIntegralValue(type, (long) index);
                break;
            }
            case VALUE_ARRAY: {
                out.writeByte(type);
                writeArray((CstArray) cst, false);
                break;
            }
            case VALUE_ANNOTATION: {
                out.writeByte(type);
                writeAnnotation(((CstAnnotation) cst).getAnnotation(),
                        false);
                break;
            }
            case VALUE_NULL: {
                out.writeByte(type);
                break;
            }
            case VALUE_BOOLEAN: {
                int value = ((CstBoolean) cst).getIntBits();
                out.writeByte(type | (value << 5));
                break;
            }
            default: {
                throw new RuntimeException("Shouldn't happen");
            }
        }
    
private voidwriteRightZeroExtendedValue(int type, long value)
Helper for {@link #writeConstant}, which writes out a right-zero-extended value.

param
type the type constant
param
value long bits of the value

        // Figure out how many bits are needed to represent the value.
        int requiredBits = 64 - Long.numberOfTrailingZeros(value);
        if (requiredBits == 0) {
            requiredBits = 1;
        }
        
        // Round up the requiredBits to a number of bytes.
        int requiredBytes = (requiredBits + 0x07) >> 3;

        // Scootch the first bits to be written down to the low-order bits.
        value >>= 64 - (requiredBytes * 8);

        /*
         * Write the header byte, which includes the type and
         * requiredBytes - 1.
         */
        out.writeByte(type | ((requiredBytes - 1) << 5));

        // Write the value, per se.
        while (requiredBytes > 0) {
            out.writeByte((byte) value);
            value >>= 8;
            requiredBytes--;
        }
    
private voidwriteSignedIntegralValue(int type, long value)
Helper for {@link #writeConstant}, which writes out the value for any signed integral type.

param
type the type constant
param
value long bits of the value

        /*
         * Figure out how many bits are needed to represent the value,
         * including a sign bit: The bit count is subtracted from 65
         * and not 64 to account for the sign bit. The xor operation
         * has the effect of leaving non-negative values alone and
         * unary complementing negative values (so that a leading zero
         * count always returns a useful number for our present
         * purpose).
         */
        int requiredBits =
            65 - Long.numberOfLeadingZeros(value ^ (value >> 63));

        // Round up the requiredBits to a number of bytes.
        int requiredBytes = (requiredBits + 0x07) >> 3;

        /*
         * Write the header byte, which includes the type and
         * requiredBytes - 1.
         */
        out.writeByte(type | ((requiredBytes - 1) << 5));

        // Write the value, per se.
        while (requiredBytes > 0) {
            out.writeByte((byte) value);
            value >>= 8;
            requiredBytes--;
        }
    
private voidwriteUnsignedIntegralValue(int type, long value)
Helper for {@link #writeConstant}, which writes out the value for any unsigned integral type.

param
type the type constant
param
value long bits of the value

        // Figure out how many bits are needed to represent the value.
        int requiredBits = 64 - Long.numberOfLeadingZeros(value);
        if (requiredBits == 0) {
            requiredBits = 1;
        }
        
        // Round up the requiredBits to a number of bytes.
        int requiredBytes = (requiredBits + 0x07) >> 3;

        /*
         * Write the header byte, which includes the type and
         * requiredBytes - 1.
         */
        out.writeByte(type | ((requiredBytes - 1) << 5));

        // Write the value, per se.
        while (requiredBytes > 0) {
            out.writeByte((byte) value);
            value >>= 8;
            requiredBytes--;
        }