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     * Gets the number of bytes in the signed LEB128 encoding of the
53     * given value.
54     *
55     * @param value the value in question
56     * @return its write size, in bytes
57     */
58    public static int signedLeb128Size(int value) {
59        // TODO: This could be much cleverer.
60
61        int remaining = value >> 7;
62        int count = 0;
63        boolean hasMore = true;
64        int end = ((value & Integer.MIN_VALUE) == 0) ? 0 : -1;
65
66        while (hasMore) {
67            hasMore = (remaining != end)
68                || ((remaining & 1) != ((value >> 6) & 1));
69
70            value = remaining;
71            remaining >>= 7;
72            count++;
73        }
74
75        return count;
76    }
77
78    /**
79     * Reads an signed integer from {@code in}.
80     */
81    public static int readSignedLeb128(ByteInput in) {
82        int result = 0;
83        int cur;
84        int count = 0;
85        int signBits = -1;
86
87        do {
88            cur = in.readByte() & 0xff;
89            result |= (cur & 0x7f) << (count * 7);
90            signBits <<= 7;
91            count++;
92        } while (((cur & 0x80) == 0x80) && count < 5);
93
94        if ((cur & 0x80) == 0x80) {
95            throw new DexException("invalid LEB128 sequence");
96        }
97
98        // Sign extend if appropriate
99        if (((signBits >> 1) & result) != 0 ) {
100            result |= signBits;
101        }
102
103        return result;
104    }
105
106    /**
107     * Reads an unsigned integer from {@code in}.
108     */
109    public static int readUnsignedLeb128(ByteInput in) {
110        int result = 0;
111        int cur;
112        int count = 0;
113
114        do {
115            cur = in.readByte() & 0xff;
116            result |= (cur & 0x7f) << (count * 7);
117            count++;
118        } while (((cur & 0x80) == 0x80) && count < 5);
119
120        if ((cur & 0x80) == 0x80) {
121            throw new DexException("invalid LEB128 sequence");
122        }
123
124        return result;
125    }
126
127    /**
128     * Writes {@code value} as an unsigned integer to {@code out}, starting at
129     * {@code offset}. Returns the number of bytes written.
130     */
131    public static void writeUnsignedLeb128(ByteOutput out, int value) {
132        int remaining = value >>> 7;
133
134        while (remaining != 0) {
135            out.writeByte((byte) ((value & 0x7f) | 0x80));
136            value = remaining;
137            remaining >>>= 7;
138        }
139
140        out.writeByte((byte) (value & 0x7f));
141    }
142
143    /**
144     * Writes {@code value} as a signed integer to {@code out}, starting at
145     * {@code offset}. Returns the number of bytes written.
146     */
147    public static void writeSignedLeb128(ByteOutput out, int value) {
148        int remaining = value >> 7;
149        boolean hasMore = true;
150        int end = ((value & Integer.MIN_VALUE) == 0) ? 0 : -1;
151
152        while (hasMore) {
153            hasMore = (remaining != end)
154                    || ((remaining & 1) != ((value >> 6) & 1));
155
156            out.writeByte((byte) ((value & 0x7f) | (hasMore ? 0x80 : 0)));
157            value = remaining;
158            remaining >>= 7;
159        }
160    }
161}
162