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