/* * 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.dex; import com.android.dex.util.ByteInput; import com.android.dex.util.ByteOutput; /** * Reads and writes DWARFv3 LEB 128 signed and unsigned integers. See DWARF v3 * section 7.6. */ public final class Leb128 { private Leb128() { } /** * Gets the number of bytes in the unsigned LEB128 encoding of the * given value. * * @param value the value in question * @return its write size, in bytes */ public static int unsignedLeb128Size(int value) { // TODO: This could be much cleverer. int remaining = value >> 7; int count = 0; while (remaining != 0) { remaining >>= 7; count++; } return count + 1; } /** * Gets the number of bytes in the signed LEB128 encoding of the * given value. * * @param value the value in question * @return its write size, in bytes */ public static int signedLeb128Size(int value) { // TODO: This could be much cleverer. int remaining = value >> 7; int count = 0; boolean hasMore = true; int end = ((value & Integer.MIN_VALUE) == 0) ? 0 : -1; while (hasMore) { hasMore = (remaining != end) || ((remaining & 1) != ((value >> 6) & 1)); value = remaining; remaining >>= 7; count++; } return count; } /** * Reads an signed integer from {@code in}. */ public static int readSignedLeb128(ByteInput in) { int result = 0; int cur; int count = 0; int signBits = -1; do { cur = in.readByte() & 0xff; result |= (cur & 0x7f) << (count * 7); signBits <<= 7; count++; } while (((cur & 0x80) == 0x80) && count < 5); if ((cur & 0x80) == 0x80) { throw new DexException("invalid LEB128 sequence"); } // Sign extend if appropriate if (((signBits >> 1) & result) != 0 ) { result |= signBits; } return result; } /** * Reads an unsigned integer from {@code in}. */ public static int readUnsignedLeb128(ByteInput in) { int result = 0; int cur; int count = 0; do { cur = in.readByte() & 0xff; result |= (cur & 0x7f) << (count * 7); count++; } while (((cur & 0x80) == 0x80) && count < 5); if ((cur & 0x80) == 0x80) { throw new DexException("invalid LEB128 sequence"); } return result; } /** * Writes {@code value} as an unsigned integer to {@code out}, starting at * {@code offset}. Returns the number of bytes written. */ public static void writeUnsignedLeb128(ByteOutput out, int value) { int remaining = value >>> 7; while (remaining != 0) { out.writeByte((byte) ((value & 0x7f) | 0x80)); value = remaining; remaining >>>= 7; } out.writeByte((byte) (value & 0x7f)); } /** * Writes {@code value} as a signed integer to {@code out}, starting at * {@code offset}. Returns the number of bytes written. */ public static void writeSignedLeb128(ByteOutput out, int value) { int remaining = value >> 7; boolean hasMore = true; int end = ((value & Integer.MIN_VALUE) == 0) ? 0 : -1; while (hasMore) { hasMore = (remaining != end) || ((remaining & 1) != ((value >> 6) & 1)); out.writeByte((byte) ((value & 0x7f) | (hasMore ? 0x80 : 0))); value = remaining; remaining >>= 7; } } }