1 package mockit.asm.util;
2
3 import edu.umd.cs.findbugs.annotations.NonNull;
4
5 import org.checkerframework.checker.index.qual.NonNegative;
6
7
8
9
10
11 @SuppressWarnings({ "NumericCastThatLosesPrecision", "CharUsedInArithmeticContext" })
12 public final class ByteVector {
13
14
15
16 @NonNull
17 private byte[] data;
18
19
20
21
22 @NonNegative
23 private int length;
24
25
26
27
28 public ByteVector() {
29 data = new byte[64];
30 }
31
32
33
34
35 public ByteVector(@NonNegative int initialSize) {
36 data = new byte[initialSize];
37 }
38
39
40
41
42 @NonNull
43 public byte[] getData() {
44 return data;
45 }
46
47
48
49
50 @NonNegative
51 public int getLength() {
52 return length;
53 }
54
55
56
57
58 public void setLength(@NonNegative int length) {
59 this.length = length;
60 }
61
62
63
64
65
66
67 @NonNull
68 public ByteVector putByte(int b) {
69 int len = getLengthEnlargingIfNeeded(1);
70 data[len] = (byte) b;
71 len++;
72 length = len;
73 return this;
74 }
75
76 @NonNegative
77 private int getLengthEnlargingIfNeeded(@NonNegative int bytesToAdd) {
78 int len = length;
79
80 if (len + bytesToAdd > data.length) {
81 enlarge(bytesToAdd);
82 }
83
84 return len;
85 }
86
87
88
89
90
91
92
93 private void enlarge(@NonNegative int size) {
94 int length1 = 2 * data.length;
95 int length2 = length + size;
96 byte[] newData = new byte[length1 > length2 ? length1 : length2];
97 System.arraycopy(data, 0, newData, 0, length);
98 data = newData;
99 }
100
101
102
103
104
105
106 @NonNull
107 public ByteVector put11(int b1, int b2) {
108 int len = getLengthEnlargingIfNeeded(2);
109 byte[] bytes = data;
110 bytes[len] = (byte) b1;
111 len++;
112 bytes[len] = (byte) b2;
113 len++;
114 length = len;
115 return this;
116 }
117
118
119
120
121
122
123 @NonNull
124 public ByteVector putShort(int s) {
125 return put11(s >>> 8, s);
126 }
127
128
129
130
131
132
133 @NonNull
134 public ByteVector put12(int b, int s) {
135 int len = getLengthEnlargingIfNeeded(3);
136 byte[] bytes = data;
137 bytes[len] = (byte) b;
138 len++;
139 bytes[len] = (byte) (s >>> 8);
140 len++;
141 bytes[len] = (byte) s;
142 len++;
143 length = len;
144 return this;
145 }
146
147
148
149
150
151
152 @NonNull
153 public ByteVector putInt(int i) {
154 int len = getLengthEnlargingIfNeeded(4);
155 byte[] bytes = data;
156 bytes[len] = (byte) (i >>> 24);
157 len++;
158 bytes[len] = (byte) (i >>> 16);
159 len++;
160 bytes[len] = (byte) (i >>> 8);
161 len++;
162 bytes[len] = (byte) i;
163 len++;
164 length = len;
165 return this;
166 }
167
168
169
170
171 public void putLong(long l) {
172 int i1 = (int) (l >>> 32);
173 int i2 = (int) l;
174 putInt(i1);
175 putInt(i2);
176 }
177
178
179
180
181
182
183
184 public void putUTF8(@NonNull String utf8String) {
185 int charLength = utf8String.length();
186
187 if (charLength > 65535) {
188 throw new IllegalArgumentException("String too long: " + charLength);
189 }
190
191 int len = getLengthEnlargingIfNeeded(2 + charLength);
192 byte[] characters = data;
193
194
195
196
197
198 characters[len] = (byte) (charLength >>> 8);
199 len++;
200 characters[len] = (byte) charLength;
201 len++;
202
203 for (int i = 0; i < charLength; i++) {
204 char c = utf8String.charAt(i);
205
206 if (c >= '\001' && c <= '\177') {
207 characters[len] = (byte) c;
208 len++;
209 } else {
210 length = len;
211 encodeUTF8(utf8String, i);
212 }
213 }
214
215 length = len;
216 }
217
218
219
220
221
222
223
224
225
226
227
228
229 private void encodeUTF8(@NonNull String utf8String, @NonNegative int startIndex) {
230 int byteLength = computeByteLength(utf8String, startIndex);
231
232 if (byteLength > 65535) {
233 throw new IllegalArgumentException("String too long for UTF8 encoding: " + byteLength);
234 }
235
236 int start = length - startIndex - 2;
237
238 if (start >= 0) {
239 data[start] = (byte) (byteLength >>> 8);
240 data[start + 1] = (byte) byteLength;
241 }
242
243 if (length + byteLength - startIndex > data.length) {
244 enlarge(byteLength - startIndex);
245 }
246
247 putEncodedCharacters(utf8String, startIndex);
248 }
249
250 @NonNegative
251 private static int computeByteLength(@NonNull String utf8String, @NonNegative int startIndex) {
252 int byteLength = startIndex;
253
254 for (int i = startIndex, n = utf8String.length(); i < n; i++) {
255 char c = utf8String.charAt(i);
256
257 if (c >= '\001' && c <= '\177') {
258 byteLength++;
259 } else if (c > '\u07FF') {
260 byteLength += 3;
261 } else {
262 byteLength += 2;
263 }
264 }
265
266 return byteLength;
267 }
268
269 private void putEncodedCharacters(@NonNull String utf8String, @NonNegative int startIndex) {
270 byte[] characters = data;
271 int len = length;
272
273 for (int i = startIndex, n = utf8String.length(); i < n; i++) {
274 char c = utf8String.charAt(i);
275
276 if (c >= '\001' && c <= '\177') {
277 characters[len] = (byte) c;
278 } else {
279 if (c > '\u07FF') {
280 characters[len] = (byte) (0xE0 | c >> 12 & 0xF);
281 len++;
282 characters[len] = (byte) (0x80 | c >> 6 & 0x3F);
283 } else {
284 characters[len] = (byte) (0xC0 | c >> 6 & 0x1F);
285 }
286 len++;
287
288 characters[len] = (byte) (0x80 | c & 0x3F);
289 }
290 len++;
291 }
292
293 length = len;
294 }
295
296
297
298
299
300
301
302
303
304
305
306 public void putByteArray(@NonNull byte[] bytes, @NonNegative int offset, @NonNegative int numBytes) {
307 int len = getLengthEnlargingIfNeeded(numBytes);
308 System.arraycopy(bytes, offset, data, len, numBytes);
309 length += numBytes;
310 }
311
312 public void putByteVector(@NonNull ByteVector another) {
313 putByteArray(another.data, 0, another.length);
314 }
315
316 public void roundUpLength() {
317 int newLength = (4 - length % 4) % 4;
318 getLengthEnlargingIfNeeded(newLength);
319 length += newLength;
320 }
321 }