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.dex;
18
19import com.android.dex.util.ByteInput;
20import com.android.dex.util.ByteOutput;
21
22/**
23 * Reads and writes DWARFv3 LEB 128 signed and unsigned integers. See DWARF v3
24 * section 7.6.
25 */
26public final class Leb128 {
27    private Leb128() {
28    }
29
30    /**
31     * Gets the number of bytes in the unsigned LEB128 encoding of the
32     * given value.
33     *
34     * @param value the value in question
35     * @return its write size, in bytes
36     */
37    public static int unsignedLeb128Size(int value) {
38        // TODO: This could be much cleverer.
39
40        int remaining = value >> 7;
41        int count = 0;
42
43        while (remaining != 0) {
44            remaining >>= 7;
45            count++;
46        }
47
48        return count + 1;
49    }
50
51    /**
52     * Reads an signed integer from {@code in}.
53     */
54    public static int readSignedLeb128(ByteInput in) {
55        int result = 0;
56        int cur;
57        int count = 0;
58        int signBits = -1;
59
60        do {
61            cur = in.readByte() & 0xff;
62            result |= (cur & 0x7f) << (count * 7);
63            signBits <<= 7;
64            count++;
65        } while (((cur & 0x80) == 0x80) && count < 5);
66
67        if ((cur & 0x80) == 0x80) {
68            throw new DexException("invalid LEB128 sequence");
69        }
70
71        // Sign extend if appropriate
72        if (((signBits >> 1) & result) != 0 ) {
73            result |= signBits;
74        }
75
76        return result;
77    }
78
79    /**
80     * Reads an unsigned integer from {@code in}.
81     */
82    public static int readUnsignedLeb128(ByteInput in) {
83        int result = 0;
84        int cur;
85        int count = 0;
86
87        do {
88            cur = in.readByte() & 0xff;
89            result |= (cur & 0x7f) << (count * 7);
90            count++;
91        } while (((cur & 0x80) == 0x80) && count < 5);
92
93        if ((cur & 0x80) == 0x80) {
94            throw new DexException("invalid LEB128 sequence");
95        }
96
97        return result;
98    }
99
100    /**
101     * Writes {@code value} as an unsigned integer to {@code out}, starting at
102     * {@code offset}. Returns the number of bytes written.
103     */
104    public static void writeUnsignedLeb128(ByteOutput out, int value) {
105        int remaining = value >>> 7;
106
107        while (remaining != 0) {
108            out.writeByte((byte) ((value & 0x7f) | 0x80));
109            value = remaining;
110            remaining >>>= 7;
111        }
112
113        out.writeByte((byte) (value & 0x7f));
114    }
115
116    /**
117     * Writes {@code value} as a signed integer to {@code out}, starting at
118     * {@code offset}. Returns the number of bytes written.
119     */
120    public static void writeSignedLeb128(ByteOutput out, int value) {
121        int remaining = value >> 7;
122        boolean hasMore = true;
123        int end = ((value & Integer.MIN_VALUE) == 0) ? 0 : -1;
124
125        while (hasMore) {
126            hasMore = (remaining != end)
127                    || ((remaining & 1) != ((value >> 6) & 1));
128
129            out.writeByte((byte) ((value & 0x7f) | (hasMore ? 0x80 : 0)));
130            value = remaining;
131            remaining >>= 7;
132        }
133    }
134}
135