|  | // Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file | 
|  | // for details. All rights reserved. Use of this source code is governed by a | 
|  | // BSD-style license that can be found in the LICENSE file. | 
|  | package com.android.tools.r8.utils; | 
|  |  | 
|  | import com.android.tools.r8.dex.DexReader; | 
|  | import com.android.tools.r8.dex.DexOutputBuffer; | 
|  |  | 
|  | public class EncodedValueUtils { | 
|  |  | 
|  | public static long parseSigned(DexReader dexReader, int numberOfBytes) { | 
|  | assert numberOfBytes > 0; | 
|  | long result = 0; | 
|  | int shift = 0; | 
|  | for (int i = 1; i < numberOfBytes; i++) { | 
|  | result |= ((long) (dexReader.get() & 0xFF)) << shift; | 
|  | shift += 8; | 
|  | } | 
|  | // Let the last byte sign-extend into any remaining bytes. | 
|  | return result | (((long) dexReader.get()) << shift); | 
|  | } | 
|  |  | 
|  | // Inspired by com.android.dex.EncodedValueCodec | 
|  | public static int putSigned(DexOutputBuffer outputBuffer, long value, int expectedSize) { | 
|  | int bit_size = Long.SIZE + 1 - Long.numberOfLeadingZeros(value ^ (value >> (Long.SIZE - 1))); | 
|  | int size = Math.max((bit_size + Byte.SIZE - 1) / Byte.SIZE, 1); | 
|  | assert size > 0 && size <= expectedSize; | 
|  | for (int i = 0; i < size; i++) { | 
|  | outputBuffer.putByte((byte) value); | 
|  | value >>= Byte.SIZE; | 
|  | } | 
|  | return size; | 
|  | } | 
|  |  | 
|  | // Inspired by com.android.dex.EncodedValueCodec | 
|  | public static byte[] encodeSigned(long value) { | 
|  | int bit_size = Long.SIZE + 1 - Long.numberOfLeadingZeros(value ^ (value >> (Long.SIZE - 1))); | 
|  | int size = Math.max((bit_size + Byte.SIZE - 1) / Byte.SIZE, 1); | 
|  | byte[] result = new byte[size]; | 
|  | for (int i = 0; i < size; i++) { | 
|  | result[i] = (byte) value; | 
|  | value >>= Byte.SIZE; | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | public static long parseUnsigned(DexReader dexReader, int numberOfBytes) { | 
|  | assert numberOfBytes > 0; | 
|  | long result = 0; | 
|  | int shift = 0; | 
|  | for (int i = 0; i < numberOfBytes; i++) { | 
|  | result |= ((long) (dexReader.get() & 0xFF)) << shift; | 
|  | shift += 8; | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | // Inspired by com.android.dex.EncodedValueCodec | 
|  | public static int putUnsigned(DexOutputBuffer outputBuffer, long value, | 
|  | int expectedSize) { | 
|  | int bit_size = Long.SIZE - Long.numberOfLeadingZeros(value); | 
|  | int size = Math.max((bit_size + Byte.SIZE - 1) / Byte.SIZE, 1); | 
|  | assert size > 0 && size <= expectedSize; | 
|  | for (int i = 0; i < size; i++) { | 
|  | outputBuffer.putByte((byte) value); | 
|  | value >>= Byte.SIZE; | 
|  | } | 
|  | return size; | 
|  | } | 
|  |  | 
|  | public static byte[] encodeUnsigned(long value) { | 
|  | int bit_size = Long.SIZE - Long.numberOfLeadingZeros(value); | 
|  | int size = Math.max((bit_size + Byte.SIZE - 1) / Byte.SIZE, 1); | 
|  | byte[] result = new byte[size]; | 
|  | for (int i = 0; i < size; i++) { | 
|  | result[i] = (byte) value; | 
|  | value >>= Byte.SIZE; | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | public static int putBitsFromRightZeroExtended(DexOutputBuffer outputBuffer, long value, | 
|  | int expectedSize) { | 
|  | int bit_size = Long.SIZE - Long.numberOfTrailingZeros(value); | 
|  | int size = (bit_size - 1) / Byte.SIZE + 1; | 
|  | assert size > 0 && size <= expectedSize; | 
|  | value >>= Long.SIZE - (size * Byte.SIZE); // shift trailing zeros. | 
|  | for (int i = 0; i < size; i++) { | 
|  | outputBuffer.putByte((byte) value); | 
|  | value >>= Byte.SIZE; | 
|  | } | 
|  | return size; | 
|  | } | 
|  |  | 
|  | private static byte[] encodeBitsFromRightZeroExtended(long value) { | 
|  | int bit_size = Long.SIZE - Long.numberOfTrailingZeros(value); | 
|  | int size = (bit_size - 1) / Byte.SIZE + 1; | 
|  | value >>= Long.SIZE - (size * Byte.SIZE); // shift trailing zeros. | 
|  | byte[] result = new byte[size]; | 
|  | for (int i = 0; i < size; i++) { | 
|  | result[i] = (byte) value; | 
|  | value >>= Byte.SIZE; | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | public static float parseFloat(DexReader dexReader, int numberOfBytes) { | 
|  | long bits = | 
|  | parseUnsigned(dexReader, numberOfBytes) << ((Float.BYTES - numberOfBytes) * Byte.SIZE); | 
|  | return Float.intBitsToFloat((int) bits); | 
|  | } | 
|  |  | 
|  | public static int putFloat(DexOutputBuffer outputBuffer, float value) { | 
|  | long bits = ((long) Float.floatToIntBits(value)) << 32; | 
|  | return EncodedValueUtils.putBitsFromRightZeroExtended(outputBuffer, bits, Float.BYTES); | 
|  | } | 
|  |  | 
|  | public static byte[] encodeFloat(float value) { | 
|  | long tmp = ((long) Float.floatToIntBits(value)) << 32; | 
|  | byte[] result = EncodedValueUtils.encodeBitsFromRightZeroExtended(tmp); | 
|  | assert result.length <= Float.BYTES; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | public static double parseDouble(DexReader dexReader, int numberOfBytes) { | 
|  | long bits = | 
|  | parseUnsigned(dexReader, numberOfBytes) << ((Double.BYTES - numberOfBytes) * Byte.SIZE); | 
|  | return Double.longBitsToDouble(bits); | 
|  | } | 
|  |  | 
|  | public static int putDouble(DexOutputBuffer outputBuffer, double value) { | 
|  | long bits = Double.doubleToLongBits(value); | 
|  | return EncodedValueUtils.putBitsFromRightZeroExtended(outputBuffer, bits, Double.BYTES); | 
|  | } | 
|  |  | 
|  | public static byte[] encodeDouble(double value) { | 
|  | long tmp = Double.doubleToLongBits(value); | 
|  | byte[] result = EncodedValueUtils.encodeBitsFromRightZeroExtended(tmp); | 
|  | assert result.length <= Double.BYTES; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | } | 
|  |  |