Home | History | Annotate | Download | only in file
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.dexgen.dex.file;
     18 
     19 import com.android.dexgen.rop.annotation.Annotation;
     20 import com.android.dexgen.rop.annotation.NameValuePair;
     21 import com.android.dexgen.rop.cst.Constant;
     22 import com.android.dexgen.rop.cst.CstAnnotation;
     23 import com.android.dexgen.rop.cst.CstArray;
     24 import com.android.dexgen.rop.cst.CstBoolean;
     25 import com.android.dexgen.rop.cst.CstByte;
     26 import com.android.dexgen.rop.cst.CstChar;
     27 import com.android.dexgen.rop.cst.CstDouble;
     28 import com.android.dexgen.rop.cst.CstEnumRef;
     29 import com.android.dexgen.rop.cst.CstFieldRef;
     30 import com.android.dexgen.rop.cst.CstFloat;
     31 import com.android.dexgen.rop.cst.CstInteger;
     32 import com.android.dexgen.rop.cst.CstKnownNull;
     33 import com.android.dexgen.rop.cst.CstLiteralBits;
     34 import com.android.dexgen.rop.cst.CstLong;
     35 import com.android.dexgen.rop.cst.CstMethodRef;
     36 import com.android.dexgen.rop.cst.CstShort;
     37 import com.android.dexgen.rop.cst.CstString;
     38 import com.android.dexgen.rop.cst.CstType;
     39 import com.android.dexgen.rop.cst.CstUtf8;
     40 import com.android.dexgen.util.AnnotatedOutput;
     41 import com.android.dexgen.util.Hex;
     42 
     43 import java.util.Collection;
     44 
     45 /**
     46  * Handler for writing out {@code encoded_values} and parts
     47  * thereof.
     48  */
     49 public final class ValueEncoder {
     50     /** annotation value type constant: {@code byte} */
     51     private static final int VALUE_BYTE = 0x00;
     52 
     53     /** annotation value type constant: {@code short} */
     54     private static final int VALUE_SHORT = 0x02;
     55 
     56     /** annotation value type constant: {@code char} */
     57     private static final int VALUE_CHAR = 0x03;
     58 
     59     /** annotation value type constant: {@code int} */
     60     private static final int VALUE_INT = 0x04;
     61 
     62     /** annotation value type constant: {@code long} */
     63     private static final int VALUE_LONG = 0x06;
     64 
     65     /** annotation value type constant: {@code float} */
     66     private static final int VALUE_FLOAT = 0x10;
     67 
     68     /** annotation value type constant: {@code double} */
     69     private static final int VALUE_DOUBLE = 0x11;
     70 
     71     /** annotation value type constant: {@code string} */
     72     private static final int VALUE_STRING = 0x17;
     73 
     74     /** annotation value type constant: {@code type} */
     75     private static final int VALUE_TYPE = 0x18;
     76 
     77     /** annotation value type constant: {@code field} */
     78     private static final int VALUE_FIELD = 0x19;
     79 
     80     /** annotation value type constant: {@code method} */
     81     private static final int VALUE_METHOD = 0x1a;
     82 
     83     /** annotation value type constant: {@code enum} */
     84     private static final int VALUE_ENUM = 0x1b;
     85 
     86     /** annotation value type constant: {@code array} */
     87     private static final int VALUE_ARRAY = 0x1c;
     88 
     89     /** annotation value type constant: {@code annotation} */
     90     private static final int VALUE_ANNOTATION = 0x1d;
     91 
     92     /** annotation value type constant: {@code null} */
     93     private static final int VALUE_NULL = 0x1e;
     94 
     95     /** annotation value type constant: {@code boolean} */
     96     private static final int VALUE_BOOLEAN = 0x1f;
     97 
     98     /** {@code non-null;} file being written */
     99     private final DexFile file;
    100 
    101     /** {@code non-null;} output stream to write to */
    102     private final AnnotatedOutput out;
    103 
    104     /**
    105      * Construct an instance.
    106      *
    107      * @param file {@code non-null;} file being written
    108      * @param out {@code non-null;} output stream to write to
    109      */
    110     public ValueEncoder(DexFile file, AnnotatedOutput out) {
    111         if (file == null) {
    112             throw new NullPointerException("file == null");
    113         }
    114 
    115         if (out == null) {
    116             throw new NullPointerException("out == null");
    117         }
    118 
    119         this.file = file;
    120         this.out = out;
    121     }
    122 
    123     /**
    124      * Writes out the encoded form of the given constant.
    125      *
    126      * @param cst {@code non-null;} the constant to write
    127      */
    128     public void writeConstant(Constant cst) {
    129         int type = constantToValueType(cst);
    130         int arg;
    131 
    132         switch (type) {
    133             case VALUE_BYTE:
    134             case VALUE_SHORT:
    135             case VALUE_INT:
    136             case VALUE_LONG: {
    137                 long value = ((CstLiteralBits) cst).getLongBits();
    138                 writeSignedIntegralValue(type, value);
    139                 break;
    140             }
    141             case VALUE_CHAR: {
    142                 long value = ((CstLiteralBits) cst).getLongBits();
    143                 writeUnsignedIntegralValue(type, value);
    144                 break;
    145             }
    146             case VALUE_FLOAT: {
    147                 // Shift value left 32 so that right-zero-extension works.
    148                 long value = ((CstFloat) cst).getLongBits() << 32;
    149                 writeRightZeroExtendedValue(type, value);
    150                 break;
    151             }
    152             case VALUE_DOUBLE: {
    153                 long value = ((CstDouble) cst).getLongBits();
    154                 writeRightZeroExtendedValue(type, value);
    155                 break;
    156             }
    157             case VALUE_STRING: {
    158                 int index = file.getStringIds().indexOf((CstString) cst);
    159                 writeUnsignedIntegralValue(type, (long) index);
    160                 break;
    161             }
    162             case VALUE_TYPE: {
    163                 int index = file.getTypeIds().indexOf((CstType) cst);
    164                 writeUnsignedIntegralValue(type, (long) index);
    165                 break;
    166             }
    167             case VALUE_FIELD: {
    168                 int index = file.getFieldIds().indexOf((CstFieldRef) cst);
    169                 writeUnsignedIntegralValue(type, (long) index);
    170                 break;
    171             }
    172             case VALUE_METHOD: {
    173                 int index = file.getMethodIds().indexOf((CstMethodRef) cst);
    174                 writeUnsignedIntegralValue(type, (long) index);
    175                 break;
    176             }
    177             case VALUE_ENUM: {
    178                 CstFieldRef fieldRef = ((CstEnumRef) cst).getFieldRef();
    179                 int index = file.getFieldIds().indexOf(fieldRef);
    180                 writeUnsignedIntegralValue(type, (long) index);
    181                 break;
    182             }
    183             case VALUE_ARRAY: {
    184                 out.writeByte(type);
    185                 writeArray((CstArray) cst, false);
    186                 break;
    187             }
    188             case VALUE_ANNOTATION: {
    189                 out.writeByte(type);
    190                 writeAnnotation(((CstAnnotation) cst).getAnnotation(),
    191                         false);
    192                 break;
    193             }
    194             case VALUE_NULL: {
    195                 out.writeByte(type);
    196                 break;
    197             }
    198             case VALUE_BOOLEAN: {
    199                 int value = ((CstBoolean) cst).getIntBits();
    200                 out.writeByte(type | (value << 5));
    201                 break;
    202             }
    203             default: {
    204                 throw new RuntimeException("Shouldn't happen");
    205             }
    206         }
    207     }
    208 
    209     /**
    210      * Gets the value type for the given constant.
    211      *
    212      * @param cst {@code non-null;} the constant
    213      * @return the value type; one of the {@code VALUE_*} constants
    214      * defined by this class
    215      */
    216     private static int constantToValueType(Constant cst) {
    217         /*
    218          * TODO: Constant should probable have an associated enum, so this
    219          * can be a switch().
    220          */
    221         if (cst instanceof CstByte) {
    222             return VALUE_BYTE;
    223         } else if (cst instanceof CstShort) {
    224             return VALUE_SHORT;
    225         } else if (cst instanceof CstChar) {
    226             return VALUE_CHAR;
    227         } else if (cst instanceof CstInteger) {
    228             return VALUE_INT;
    229         } else if (cst instanceof CstLong) {
    230             return VALUE_LONG;
    231         } else if (cst instanceof CstFloat) {
    232             return VALUE_FLOAT;
    233         } else if (cst instanceof CstDouble) {
    234             return VALUE_DOUBLE;
    235         } else if (cst instanceof CstString) {
    236             return VALUE_STRING;
    237         } else if (cst instanceof CstType) {
    238             return VALUE_TYPE;
    239         } else if (cst instanceof CstFieldRef) {
    240             return VALUE_FIELD;
    241         } else if (cst instanceof CstMethodRef) {
    242             return VALUE_METHOD;
    243         } else if (cst instanceof CstEnumRef) {
    244             return VALUE_ENUM;
    245         } else if (cst instanceof CstArray) {
    246             return VALUE_ARRAY;
    247         } else if (cst instanceof CstAnnotation) {
    248             return VALUE_ANNOTATION;
    249         } else if (cst instanceof CstKnownNull) {
    250             return VALUE_NULL;
    251         } else if (cst instanceof CstBoolean) {
    252             return VALUE_BOOLEAN;
    253         } else {
    254             throw new RuntimeException("Shouldn't happen");
    255         }
    256     }
    257 
    258     /**
    259      * Writes out the encoded form of the given array, that is, as
    260      * an {@code encoded_array} and not including a
    261      * {@code value_type} prefix. If the output stream keeps
    262      * (debugging) annotations and {@code topLevel} is
    263      * {@code true}, then this method will write (debugging)
    264      * annotations.
    265      *
    266      * @param array {@code non-null;} array instance to write
    267      * @param topLevel {@code true} iff the given annotation is the
    268      * top-level annotation or {@code false} if it is a sub-annotation
    269      * of some other annotation
    270      */
    271     public void writeArray(CstArray array, boolean topLevel) {
    272         boolean annotates = topLevel && out.annotates();
    273         CstArray.List list = ((CstArray) array).getList();
    274         int size = list.size();
    275 
    276         if (annotates) {
    277             out.annotate("  size: " + Hex.u4(size));
    278         }
    279 
    280         out.writeUnsignedLeb128(size);
    281 
    282         for (int i = 0; i < size; i++) {
    283             Constant cst = list.get(i);
    284             if (annotates) {
    285                 out.annotate("  [" + Integer.toHexString(i) + "] " +
    286                         constantToHuman(cst));
    287             }
    288             writeConstant(cst);
    289         }
    290 
    291         if (annotates) {
    292             out.endAnnotation();
    293         }
    294     }
    295 
    296     /**
    297      * Writes out the encoded form of the given annotation, that is,
    298      * as an {@code encoded_annotation} and not including a
    299      * {@code value_type} prefix. If the output stream keeps
    300      * (debugging) annotations and {@code topLevel} is
    301      * {@code true}, then this method will write (debugging)
    302      * annotations.
    303      *
    304      * @param annotation {@code non-null;} annotation instance to write
    305      * @param topLevel {@code true} iff the given annotation is the
    306      * top-level annotation or {@code false} if it is a sub-annotation
    307      * of some other annotation
    308      */
    309     public void writeAnnotation(Annotation annotation, boolean topLevel) {
    310         boolean annotates = topLevel && out.annotates();
    311         StringIdsSection stringIds = file.getStringIds();
    312         TypeIdsSection typeIds = file.getTypeIds();
    313 
    314         CstType type = annotation.getType();
    315         int typeIdx = typeIds.indexOf(type);
    316 
    317         if (annotates) {
    318             out.annotate("  type_idx: " + Hex.u4(typeIdx) + " // " +
    319                     type.toHuman());
    320         }
    321 
    322         out.writeUnsignedLeb128(typeIds.indexOf(annotation.getType()));
    323 
    324         Collection<NameValuePair> pairs = annotation.getNameValuePairs();
    325         int size = pairs.size();
    326 
    327         if (annotates) {
    328             out.annotate("  size: " + Hex.u4(size));
    329         }
    330 
    331         out.writeUnsignedLeb128(size);
    332 
    333         int at = 0;
    334         for (NameValuePair pair : pairs) {
    335             CstUtf8 name = pair.getName();
    336             int nameIdx = stringIds.indexOf(name);
    337             Constant value = pair.getValue();
    338 
    339             if (annotates) {
    340                 out.annotate(0, "  elements[" + at + "]:");
    341                 at++;
    342                 out.annotate("    name_idx: " + Hex.u4(nameIdx) + " // " +
    343                         name.toHuman());
    344             }
    345 
    346             out.writeUnsignedLeb128(nameIdx);
    347 
    348             if (annotates) {
    349                 out.annotate("    value: " + constantToHuman(value));
    350             }
    351 
    352             writeConstant(value);
    353         }
    354 
    355         if (annotates) {
    356             out.endAnnotation();
    357         }
    358     }
    359 
    360     /**
    361      * Gets the colloquial type name and human form of the type of the
    362      * given constant, when used as an encoded value.
    363      *
    364      * @param cst {@code non-null;} the constant
    365      * @return {@code non-null;} its type name and human form
    366      */
    367     public static String constantToHuman(Constant cst) {
    368         int type = constantToValueType(cst);
    369 
    370         if (type == VALUE_NULL) {
    371             return "null";
    372         }
    373 
    374         StringBuilder sb = new StringBuilder();
    375 
    376         sb.append(cst.typeName());
    377         sb.append(' ');
    378         sb.append(cst.toHuman());
    379 
    380         return sb.toString();
    381     }
    382 
    383     /**
    384      * Helper for {@link #writeConstant}, which writes out the value
    385      * for any signed integral type.
    386      *
    387      * @param type the type constant
    388      * @param value {@code long} bits of the value
    389      */
    390     private void writeSignedIntegralValue(int type, long value) {
    391         /*
    392          * Figure out how many bits are needed to represent the value,
    393          * including a sign bit: The bit count is subtracted from 65
    394          * and not 64 to account for the sign bit. The xor operation
    395          * has the effect of leaving non-negative values alone and
    396          * unary complementing negative values (so that a leading zero
    397          * count always returns a useful number for our present
    398          * purpose).
    399          */
    400         int requiredBits =
    401             65 - Long.numberOfLeadingZeros(value ^ (value >> 63));
    402 
    403         // Round up the requiredBits to a number of bytes.
    404         int requiredBytes = (requiredBits + 0x07) >> 3;
    405 
    406         /*
    407          * Write the header byte, which includes the type and
    408          * requiredBytes - 1.
    409          */
    410         out.writeByte(type | ((requiredBytes - 1) << 5));
    411 
    412         // Write the value, per se.
    413         while (requiredBytes > 0) {
    414             out.writeByte((byte) value);
    415             value >>= 8;
    416             requiredBytes--;
    417         }
    418     }
    419 
    420     /**
    421      * Helper for {@link #writeConstant}, which writes out the value
    422      * for any unsigned integral type.
    423      *
    424      * @param type the type constant
    425      * @param value {@code long} bits of the value
    426      */
    427     private void writeUnsignedIntegralValue(int type, long value) {
    428         // Figure out how many bits are needed to represent the value.
    429         int requiredBits = 64 - Long.numberOfLeadingZeros(value);
    430         if (requiredBits == 0) {
    431             requiredBits = 1;
    432         }
    433 
    434         // Round up the requiredBits to a number of bytes.
    435         int requiredBytes = (requiredBits + 0x07) >> 3;
    436 
    437         /*
    438          * Write the header byte, which includes the type and
    439          * requiredBytes - 1.
    440          */
    441         out.writeByte(type | ((requiredBytes - 1) << 5));
    442 
    443         // Write the value, per se.
    444         while (requiredBytes > 0) {
    445             out.writeByte((byte) value);
    446             value >>= 8;
    447             requiredBytes--;
    448         }
    449     }
    450 
    451     /**
    452      * Helper for {@link #writeConstant}, which writes out a
    453      * right-zero-extended value.
    454      *
    455      * @param type the type constant
    456      * @param value {@code long} bits of the value
    457      */
    458     private void writeRightZeroExtendedValue(int type, long value) {
    459         // Figure out how many bits are needed to represent the value.
    460         int requiredBits = 64 - Long.numberOfTrailingZeros(value);
    461         if (requiredBits == 0) {
    462             requiredBits = 1;
    463         }
    464 
    465         // Round up the requiredBits to a number of bytes.
    466         int requiredBytes = (requiredBits + 0x07) >> 3;
    467 
    468         // Scootch the first bits to be written down to the low-order bits.
    469         value >>= 64 - (requiredBytes * 8);
    470 
    471         /*
    472          * Write the header byte, which includes the type and
    473          * requiredBytes - 1.
    474          */
    475         out.writeByte(type | ((requiredBytes - 1) << 5));
    476 
    477         // Write the value, per se.
    478         while (requiredBytes > 0) {
    479             out.writeByte((byte) value);
    480             value >>= 8;
    481             requiredBytes--;
    482         }
    483     }
    484 
    485 
    486     /**
    487      * Helper for {@code addContents()} methods, which adds
    488      * contents for a particular {@link Annotation}, calling itself
    489      * recursively should it encounter a nested annotation.
    490      *
    491      * @param file {@code non-null;} the file to add to
    492      * @param annotation {@code non-null;} the annotation to add contents for
    493      */
    494     public static void addContents(DexFile file, Annotation annotation) {
    495         TypeIdsSection typeIds = file.getTypeIds();
    496         StringIdsSection stringIds = file.getStringIds();
    497 
    498         typeIds.intern(annotation.getType());
    499 
    500         for (NameValuePair pair : annotation.getNameValuePairs()) {
    501             stringIds.intern(pair.getName());
    502             addContents(file, pair.getValue());
    503         }
    504     }
    505 
    506     /**
    507      * Helper for {@code addContents()} methods, which adds
    508      * contents for a particular constant, calling itself recursively
    509      * should it encounter a {@link CstArray} and calling {@link
    510      * #addContents(DexFile,Annotation)} recursively should it
    511      * encounter a {@link CstAnnotation}.
    512      *
    513      * @param file {@code non-null;} the file to add to
    514      * @param cst {@code non-null;} the constant to add contents for
    515      */
    516     public static void addContents(DexFile file, Constant cst) {
    517         if (cst instanceof CstAnnotation) {
    518             addContents(file, ((CstAnnotation) cst).getAnnotation());
    519         } else if (cst instanceof CstArray) {
    520             CstArray.List list = ((CstArray) cst).getList();
    521             int size = list.size();
    522             for (int i = 0; i < size; i++) {
    523                 addContents(file, list.get(i));
    524             }
    525         } else {
    526             file.internIfAppropriate(cst);
    527         }
    528     }
    529 }
    530