diff options
Diffstat (limited to 'dx/src/com/android/dx/dex/file/ValueEncoder.java')
-rw-r--r-- | dx/src/com/android/dx/dex/file/ValueEncoder.java | 532 |
1 files changed, 0 insertions, 532 deletions
diff --git a/dx/src/com/android/dx/dex/file/ValueEncoder.java b/dx/src/com/android/dx/dex/file/ValueEncoder.java deleted file mode 100644 index 02a34194f..000000000 --- a/dx/src/com/android/dx/dex/file/ValueEncoder.java +++ /dev/null @@ -1,532 +0,0 @@ -/* - * Copyright (C) 2008 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 com.android.dx.dex.file; - -import com.android.dx.rop.annotation.Annotation; -import com.android.dx.rop.annotation.NameValuePair; -import com.android.dx.rop.cst.Constant; -import com.android.dx.rop.cst.CstAnnotation; -import com.android.dx.rop.cst.CstArray; -import com.android.dx.rop.cst.CstBoolean; -import com.android.dx.rop.cst.CstByte; -import com.android.dx.rop.cst.CstChar; -import com.android.dx.rop.cst.CstDouble; -import com.android.dx.rop.cst.CstEnumRef; -import com.android.dx.rop.cst.CstFieldRef; -import com.android.dx.rop.cst.CstFloat; -import com.android.dx.rop.cst.CstInteger; -import com.android.dx.rop.cst.CstKnownNull; -import com.android.dx.rop.cst.CstLiteralBits; -import com.android.dx.rop.cst.CstLong; -import com.android.dx.rop.cst.CstMethodRef; -import com.android.dx.rop.cst.CstShort; -import com.android.dx.rop.cst.CstString; -import com.android.dx.rop.cst.CstType; -import com.android.dx.rop.cst.CstUtf8; -import com.android.dx.util.AnnotatedOutput; -import com.android.dx.util.Hex; - -import java.util.Collection; - -/** - * Handler for writing out <code>encoded_values</code> and parts - * thereof. - */ -public final class ValueEncoder { - /** annotation value type constant: <code>byte</code> */ - private static final int VALUE_BYTE = 0x00; - - /** annotation value type constant: <code>short</code> */ - private static final int VALUE_SHORT = 0x02; - - /** annotation value type constant: <code>char</code> */ - private static final int VALUE_CHAR = 0x03; - - /** annotation value type constant: <code>int</code> */ - private static final int VALUE_INT = 0x04; - - /** annotation value type constant: <code>long</code> */ - private static final int VALUE_LONG = 0x06; - - /** annotation value type constant: <code>float</code> */ - private static final int VALUE_FLOAT = 0x10; - - /** annotation value type constant: <code>double</code> */ - private static final int VALUE_DOUBLE = 0x11; - - /** annotation value type constant: <code>string</code> */ - private static final int VALUE_STRING = 0x17; - - /** annotation value type constant: <code>type</code> */ - private static final int VALUE_TYPE = 0x18; - - /** annotation value type constant: <code>field</code> */ - private static final int VALUE_FIELD = 0x19; - - /** annotation value type constant: <code>method</code> */ - private static final int VALUE_METHOD = 0x1a; - - /** annotation value type constant: <code>enum</code> */ - private static final int VALUE_ENUM = 0x1b; - - /** annotation value type constant: <code>array</code> */ - private static final int VALUE_ARRAY = 0x1c; - - /** annotation value type constant: <code>annotation</code> */ - private static final int VALUE_ANNOTATION = 0x1d; - - /** annotation value type constant: <code>null</code> */ - private static final int VALUE_NULL = 0x1e; - - /** annotation value type constant: <code>boolean</code> */ - private static final int VALUE_BOOLEAN = 0x1f; - - /** non-null; file being written */ - private final DexFile file; - - /** non-null; output stream to write to */ - private final AnnotatedOutput out; - - /** - * Construct an instance. - * - * @param file non-null; file being written - * @param out non-null; output stream to write to - */ - public ValueEncoder(DexFile file, AnnotatedOutput out) { - if (file == null) { - throw new NullPointerException("file == null"); - } - - if (out == null) { - throw new NullPointerException("out == null"); - } - - this.file = file; - this.out = out; - } - - /** - * Writes out the encoded form of the given constant. - * - * @param cst non-null; the constant to write - */ - public void writeConstant(Constant cst) { - 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"); - } - } - } - - /** - * Gets the value type for the given constant. - * - * @param cst non-null; the constant - * @return the value type; one of the <code>VALUE_*</code> constants - * defined by this class - */ - private static int constantToValueType(Constant cst) { - /* - * 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"); - } - } - - /** - * Writes out the encoded form of the given array, that is, as - * an <code>encoded_array</code> and not including a - * <code>value_type</code> prefix. If the output stream keeps - * (debugging) annotations and <code>topLevel</code> is - * <code>true</code>, then this method will write (debugging) - * annotations. - * - * @param array non-null; array instance to write - * @param topLevel <code>true</code> iff the given annotation is the - * top-level annotation or <code>false</code> if it is a sub-annotation - * of some other annotation - */ - public void writeArray(CstArray array, boolean topLevel) { - 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(); - } - } - - /** - * Writes out the encoded form of the given annotation, that is, - * as an <code>encoded_annotation</code> and not including a - * <code>value_type</code> prefix. If the output stream keeps - * (debugging) annotations and <code>topLevel</code> is - * <code>true</code>, then this method will write (debugging) - * annotations. - * - * @param annotation non-null; annotation instance to write - * @param topLevel <code>true</code> iff the given annotation is the - * top-level annotation or <code>false</code> if it is a sub-annotation - * of some other annotation - */ - public void writeAnnotation(Annotation annotation, boolean topLevel) { - 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(); - } - } - - /** - * 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 - */ - public static String constantToHuman(Constant cst) { - 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(); - } - - /** - * Helper for {@link #writeConstant}, which writes out the value - * for any signed integral type. - * - * @param type the type constant - * @param value <code>long</code> bits of the value - */ - private void writeSignedIntegralValue(int type, long 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--; - } - } - - /** - * Helper for {@link #writeConstant}, which writes out the value - * for any unsigned integral type. - * - * @param type the type constant - * @param value <code>long</code> bits of the value - */ - private void writeUnsignedIntegralValue(int type, long 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--; - } - } - - /** - * Helper for {@link #writeConstant}, which writes out a - * right-zero-extended value. - * - * @param type the type constant - * @param value <code>long</code> bits of the value - */ - private void writeRightZeroExtendedValue(int type, long 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--; - } - } - - - /** - * Helper for <code>addContents()</code> 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 - */ - public static void addContents(DexFile file, Annotation annotation) { - 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()); - } - } - - /** - * Helper for <code>addContents()</code> 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 - */ - public static void addContents(DexFile file, Constant cst) { - 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); - } - } -} |