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