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