All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.snapscript.dex.EncodedValueReader Maven / Gradle / Ivy

There is a newer version: 1.4.6
Show newest version
/*
 * Copyright (C) 2011 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 org.snapscript.dex;

import org.snapscript.dex.util.ByteInput;

/**
 * Pull parser for encoded values.
 */
public final class EncodedValueReader {
    public static final int ENCODED_BYTE = 0x00;
    public static final int ENCODED_SHORT = 0x02;
    public static final int ENCODED_CHAR = 0x03;
    public static final int ENCODED_INT = 0x04;
    public static final int ENCODED_LONG = 0x06;
    public static final int ENCODED_FLOAT = 0x10;
    public static final int ENCODED_DOUBLE = 0x11;
    public static final int ENCODED_STRING = 0x17;
    public static final int ENCODED_TYPE = 0x18;
    public static final int ENCODED_FIELD = 0x19;
    public static final int ENCODED_ENUM = 0x1b;
    public static final int ENCODED_METHOD = 0x1a;
    public static final int ENCODED_ARRAY = 0x1c;
    public static final int ENCODED_ANNOTATION = 0x1d;
    public static final int ENCODED_NULL = 0x1e;
    public static final int ENCODED_BOOLEAN = 0x1f;

    /** placeholder type if the type is not yet known */
    private static final int MUST_READ = -1;

    protected final ByteInput in;
    private int type = MUST_READ;
    private int annotationType;
    private int arg;

    public EncodedValueReader(ByteInput in) {
        this.in = in;
    }

    public EncodedValueReader(EncodedValue in) {
        this(in.asByteInput());
    }

    /**
     * Creates a new encoded value reader whose only value is the specified
     * known type. This is useful for encoded values without a type prefix,
     * such as class_def_item's encoded_array or annotation_item's
     * encoded_annotation.
     */
    public EncodedValueReader(ByteInput in, int knownType) {
        this.in = in;
        this.type = knownType;
    }

    public EncodedValueReader(EncodedValue in, int knownType) {
        this(in.asByteInput(), knownType);
    }

    /**
     * Returns the type of the next value to read.
     */
    public int peek() {
        if (type == MUST_READ) {
            int argAndType = in.readByte() & 0xff;
            type = argAndType & 0x1f;
            arg = (argAndType & 0xe0) >> 5;
        }
        return type;
    }

    /**
     * Begins reading the elements of an array, returning the array's size. The
     * caller must follow up by calling a read method for each element in the
     * array. For example, this reads a byte array: 
   {@code
     *   int arraySize = readArray();
     *   for (int i = 0, i < arraySize; i++) {
     *     readByte();
     *   }
     * }
*/ public int readArray() { checkType(ENCODED_ARRAY); type = MUST_READ; return Leb128.readUnsignedLeb128(in); } /** * Begins reading the fields of an annotation, returning the number of * fields. The caller must follow up by making alternating calls to {@link * #readAnnotationName()} and another read method. For example, this reads * an annotation whose fields are all bytes:
   {@code
     *   int fieldCount = readAnnotation();
     *   int annotationType = getAnnotationType();
     *   for (int i = 0; i < fieldCount; i++) {
     *       readAnnotationName();
     *       readByte();
     *   }
     * }
*/ public int readAnnotation() { checkType(ENCODED_ANNOTATION); type = MUST_READ; annotationType = Leb128.readUnsignedLeb128(in); return Leb128.readUnsignedLeb128(in); } /** * Returns the type of the annotation just returned by {@link * #readAnnotation()}. This method's value is undefined unless the most * recent call was to {@link #readAnnotation()}. */ public int getAnnotationType() { return annotationType; } public int readAnnotationName() { return Leb128.readUnsignedLeb128(in); } public byte readByte() { checkType(ENCODED_BYTE); type = MUST_READ; return (byte) EncodedValueCodec.readSignedInt(in, arg); } public short readShort() { checkType(ENCODED_SHORT); type = MUST_READ; return (short) EncodedValueCodec.readSignedInt(in, arg); } public char readChar() { checkType(ENCODED_CHAR); type = MUST_READ; return (char) EncodedValueCodec.readUnsignedInt(in, arg, false); } public int readInt() { checkType(ENCODED_INT); type = MUST_READ; return EncodedValueCodec.readSignedInt(in, arg); } public long readLong() { checkType(ENCODED_LONG); type = MUST_READ; return EncodedValueCodec.readSignedLong(in, arg); } public float readFloat() { checkType(ENCODED_FLOAT); type = MUST_READ; return Float.intBitsToFloat(EncodedValueCodec.readUnsignedInt(in, arg, true)); } public double readDouble() { checkType(ENCODED_DOUBLE); type = MUST_READ; return Double.longBitsToDouble(EncodedValueCodec.readUnsignedLong(in, arg, true)); } public int readString() { checkType(ENCODED_STRING); type = MUST_READ; return EncodedValueCodec.readUnsignedInt(in, arg, false); } public int readType() { checkType(ENCODED_TYPE); type = MUST_READ; return EncodedValueCodec.readUnsignedInt(in, arg, false); } public int readField() { checkType(ENCODED_FIELD); type = MUST_READ; return EncodedValueCodec.readUnsignedInt(in, arg, false); } public int readEnum() { checkType(ENCODED_ENUM); type = MUST_READ; return EncodedValueCodec.readUnsignedInt(in, arg, false); } public int readMethod() { checkType(ENCODED_METHOD); type = MUST_READ; return EncodedValueCodec.readUnsignedInt(in, arg, false); } public void readNull() { checkType(ENCODED_NULL); type = MUST_READ; } public boolean readBoolean() { checkType(ENCODED_BOOLEAN); type = MUST_READ; return arg != 0; } /** * Skips a single value, including its nested values if it is an array or * annotation. */ public void skipValue() { switch (peek()) { case ENCODED_BYTE: readByte(); break; case ENCODED_SHORT: readShort(); break; case ENCODED_CHAR: readChar(); break; case ENCODED_INT: readInt(); break; case ENCODED_LONG: readLong(); break; case ENCODED_FLOAT: readFloat(); break; case ENCODED_DOUBLE: readDouble(); break; case ENCODED_STRING: readString(); break; case ENCODED_TYPE: readType(); break; case ENCODED_FIELD: readField(); break; case ENCODED_ENUM: readEnum(); break; case ENCODED_METHOD: readMethod(); break; case ENCODED_ARRAY: for (int i = 0, size = readArray(); i < size; i++) { skipValue(); } break; case ENCODED_ANNOTATION: for (int i = 0, size = readAnnotation(); i < size; i++) { readAnnotationName(); skipValue(); } break; case ENCODED_NULL: readNull(); break; case ENCODED_BOOLEAN: readBoolean(); break; default: throw new DexException("Unexpected type: " + Integer.toHexString(type)); } } private void checkType(int expected) { if (peek() != expected) { throw new IllegalStateException( String.format("Expected %x but was %x", expected, peek())); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy