Java程序  |  299行  |  9.74 KB

/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package dex.reader;

import static dex.structure.DexEncodedValueType.*;
import dex.reader.DexFileReader.FieldIdItem;
import dex.structure.DexAnnotation;
import dex.structure.DexEncodedValue;
import dex.structure.DexEncodedValueType;

import java.util.ArrayList;
import java.util.List;

/* package */final class DexEncodedValueImpl implements DexEncodedValue {

    private final DexBuffer buffer;
    private byte typeAndValueArg;
    private DexEncodedValueType type;
    private String[] stringPool;
    private Object value;
    private int[] typeIds;
    private final FieldIdItem[] fieldIdItems;
    private final DexAnnotation annotation;

    /**
     * 
     * @param buffer
     *            the buffer with the correct position
     * @param annotation
     * @param stringPool
     * @param fieldIdItems
     */
    public DexEncodedValueImpl(DexBuffer buffer, DexAnnotation annotation,
            int[] typeIds, String[] stringPool, FieldIdItem[] fieldIdItems) {
        this.buffer = buffer;
        this.annotation = annotation;
        this.typeIds = typeIds;
        this.stringPool = stringPool;
        this.fieldIdItems = fieldIdItems;
        parseValue();
    }

    private void parseValue() {
        typeAndValueArg = buffer.readUByte();
        type = DexEncodedValueType.get(typeAndValueArg);
        int valueArg = DexEncodedValueType.valueArg(typeAndValueArg);
        switch (type) {
        case VALUE_BYTE:
            value = getByteValue(valueArg);
            break;
        case VALUE_SHORT:
            value = getShortValue(valueArg);
            break;
        case VALUE_CHAR:
            value = getCharValue(valueArg);
            break;
        case VALUE_INT:
            value = getIntValue(valueArg);
            break;
        case VALUE_LONG:
            value = getLongValue(valueArg);
            break;
        case VALUE_FLOAT:
            value = getFloatValue(valueArg);
            break;
        case VALUE_DOUBLE:
            value = getDoubleValue(valueArg);
            break;
        case VALUE_STRING:
            value = getStringValue(valueArg);
            break;
        case VALUE_TYPE:
            value = getTypeValue(valueArg);
            break;
        case VALUE_FIELD:
            value = getFieldValue(valueArg);
            break;
        case VALUE_METHOD:
            value = getMethodValue(valueArg);
            break;
        case VALUE_ENUM:
            value = getEnumValue(valueArg);
            break;
        case VALUE_ARRAY:
            value = getArrayValue(valueArg);
            break;
        case VALUE_ANNOTATION:
            value = getAnnotationValue(valueArg);
            break;
        case VALUE_NULL:
            value = getNullValue(valueArg);
            break;
        case VALUE_BOOLEAN:
            value = getBooleanValue(valueArg);
            break;
        default:
            throw new IllegalArgumentException("DexEncodedValueType " + type
                    + " not recognized");
        }
    }

    /**
     * VALUE_BOOLEAN 0x1f boolean (0...1) (none) one-bit value; 0 for false and
     * 1 for true. The bit is represented in the value_arg.
     */
    private Boolean getBooleanValue(int valueArg) {
        return valueArg == 1;
    }

    /** VALUE_NULL 0x1e (none; must be 0) (none) null reference value */
    private Object getNullValue(int valueArg) {
        return null; // must be like that!
    }

    /**
     * VALUE_ANNOTATION 0x1d (none; must be 0) encoded_annotation a
     * sub-annotation, in the format specified by "encoded_annotation Format"
     * below. The size of the value is implicit in the encoding.
     */
    private Object getAnnotationValue(int valueArg) {
        // use the buffer directly to get adjusted offset
        return new DexEncodedAnnotationImpl(buffer, annotation, typeIds,
                stringPool, fieldIdItems);
    }

    /**
     * VALUE_ARRAY 0x1c (none; must be 0) encoded_array an array of values, in
     * the format specified by "encoded_array Format" below. The size of the
     * value is implicit in the encoding.
     */
    private List<DexEncodedValue> getArrayValue(int valueArg) {
        int size = buffer.readUleb128();
        List<DexEncodedValue> values = new ArrayList<DexEncodedValue>(size);
        for (int i = 0; i < size; i++) {
            values.add(new DexEncodedValueImpl(buffer, annotation, typeIds,
                    stringPool, fieldIdItems));
        }
        return values;
    }

    /**
     * VALUE_ENUM 0x1b size - 1 (0...3) ubyte[size] unsigned (zero-extended)
     * four-byte integer value, interpreted as an index into the field_ids
     * section and representing the value of an enumerated type constant
     */
    private Object getEnumValue(int valueArg) {
        int fieldOffset = buffer.readInt(valueArg + 1);
        FieldIdItem fieldIdItem = fieldIdItems[fieldOffset];
        // FORMAT La/b/E;!CONSTANT
        String constantName = stringPool[fieldIdItem.name_idx];
        String typeName = stringPool[typeIds[fieldIdItem.type_idx]];
        return typeName + "!" + constantName;
    }

    /**
     * VALUE_METHOD 0x1a size - 1 (0...3) ubyte[size] unsigned (zero-extended)
     * four-byte integer value, interpreted as an index into the method_ids
     * section and representing a reflective method value
     */
    private Object getMethodValue(int valueArg) {
        // FIXME lookup value
        buffer.skip(valueArg + 1);
        return null;
    }

    /**
     * VALUE_FIELD 0x19 size - 1 (0...3) ubyte[size] unsigned (zero-extended)
     * four-byte integer value, interpreted as an index into the field_ids
     * section and representing a reflective field value
     */
    private Object getFieldValue(int valueArg) {
        int fieldOffset = buffer.readInt(valueArg + 1);
        FieldIdItem fieldIdItem = fieldIdItems[fieldOffset];
        // FORMAT La/b/E;!CONSTANT
        String fieldName = stringPool[fieldIdItem.name_idx];
        String typeName = stringPool[typeIds[fieldIdItem.type_idx]];
        return typeName + "!" + fieldName;
    }

    /**
     * VALUE_TYPE 0x18 size - 1 (0...3) ubyte[size] unsigned (zero-extended)
     * four-byte integer value, interpreted as an index into the type_ids
     * section and representing a reflective type/class value
     */
    private Object getTypeValue(int valueArg) {
        valueArg++; // size - 1 (0...3)
        // FIXME SPEC!! states: unsigned (zero-extended) four-byte integer value
        return stringPool[typeIds[buffer.readInt(valueArg)]];
    }

    /**
     * VALUE_STRING 0x17 size - 1 (0...3) ubyte[size] unsigned (zero-extended)
     * four-byte integer value, interpreted as an index into the string_ids
     * section and representing a string value
     */
    private Object getStringValue(int valueArg) {
        valueArg++;
        return stringPool[buffer.readInt(valueArg)];
    }

    /**
     * VALUE_DOUBLE 0x11 size - 1 (0...7) ubyte[size] eight-byte bit pattern,
     * zero-extended to the right, and interpreted as an IEEE754 64-bit floating
     * point value
     */
    private Object getDoubleValue(int valueArg) {
        return buffer.readDouble(valueArg + 1);
    }

    /**
     * VALUE_FLOAT 0x10 size - 1 (0...3) ubyte[size] four-byte bit pattern,
     * zero-extended to the right, and interpreted as an IEEE754 32-bit floating
     * point value
     */
    private Float getFloatValue(int valueArg) {
        return buffer.readFloat(valueArg + 1);
    }

    /**
     * VALUE_LONG 0x06 size - 1 (0...7) ubyte[size] signed eight-byte integer
     * value, sign-extended
     */
    private Long getLongValue(int valueArg) {
        return buffer.readLong(valueArg + 1);
    }

    /**
     * VALUE_INT 0x04 size - 1 (0...3) ubyte[size] signed four-byte integer
     * value, sign-extended
     */
    private Integer getIntValue(int valueArg) {
        return buffer.readInt(valueArg + 1);
    }

    /**
     * VALUE_CHAR 0x03 size - 1 (0...1) ubyte[size] unsigned two-byte integer
     * value, zero-extended
     */
    private Character getCharValue(int valueArg) {
        return buffer.readChar(valueArg + 1);
    }

    /**
     * VALUE_SHORT 0x02 size - 1 (0...1) ubyte[size] signed two-byte integer
     * value, sign-extended
     */
    private Short getShortValue(int valueArg) {
        return buffer.readShort(valueArg + 1);
    }

    /**
     * VALUE_BYTE 0x00 (none; must be 0) ubyte[1] signed one-byte integer value
     */
    private Byte getByteValue(int valueArg) {
        assert valueArg == 0 : "Illegal valueArg for VALUE_BYTE: " + valueArg;
        return null;
    }

    public DexEncodedValueType getType() {
        return type;
    }

    public Object getValue() {
        return value;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("=");
        if (type == VALUE_ARRAY) {
            if (getValue() instanceof List<?>) {
                List<?> values = (List<?>) getValue();
                for (Object object : values) {
                    DexEncodedValue val = (DexEncodedValue) object;
                    builder.append(val.getValue());
                }
            }
        } else {
            builder.append(getValue());
        }
        return builder.toString();
    }
}