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      */
ValueEncoder(DexFile file, AnnotatedOutput out)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      */
writeConstant(Constant cst)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      */
constantToValueType(Constant cst)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      */
writeArray(CstArray array, boolean topLevel)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      */
writeAnnotation(Annotation annotation, boolean topLevel)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      */
constantToHuman(Constant cst)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      */
writeSignedIntegralValue(int type, long value)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      */
writeUnsignedIntegralValue(int type, long value)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      */
writeRightZeroExtendedValue(int type, long value)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      */
addContents(DexFile file, Annotation annotation)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      */
addContents(DexFile file, Constant cst)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