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 
17 package com.android.dex;
18 
19 import com.android.dex.util.ByteInput;
20 import 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  */
26 public final class Leb128 {
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      */
unsignedLeb128Size(int value)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      */
readSignedLeb128(ByteInput in)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      */
readUnsignedLeb128(ByteInput in)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      */
writeUnsignedLeb128(ByteOutput out, int value)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      */
writeSignedLeb128(ByteOutput out, int value)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