1 /*
2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3  *
4  * This code is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 2 only, as
6  * published by the Free Software Foundation.  Oracle designates this
7  * particular file as subject to the "Classpath" exception as provided
8  * by Oracle in the LICENSE file that accompanied this code.
9  *
10  * This code is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13  * version 2 for more details (a copy is included in the LICENSE file that
14  * accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License version
17  * 2 along with this work; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19  *
20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21  * or visit www.oracle.com if you need additional information or have any
22  * questions.
23  */
24 
25 /*
26  * This file is available under and governed by the GNU General Public
27  * License version 2 only, as published by the Free Software Foundation.
28  * However, the following notice accompanied the original version of this
29  * file:
30  *
31  * ASM: a very small and fast Java bytecode manipulation framework
32  * Copyright (c) 2000-2011 INRIA, France Telecom
33  * All rights reserved.
34  *
35  * Redistribution and use in source and binary forms, with or without
36  * modification, are permitted provided that the following conditions
37  * are met:
38  * 1. Redistributions of source code must retain the above copyright
39  *    notice, this list of conditions and the following disclaimer.
40  * 2. Redistributions in binary form must reproduce the above copyright
41  *    notice, this list of conditions and the following disclaimer in the
42  *    documentation and/or other materials provided with the distribution.
43  * 3. Neither the name of the copyright holders nor the names of its
44  *    contributors may be used to endorse or promote products derived from
45  *    this software without specific prior written permission.
46  *
47  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
48  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
51  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
52  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
53  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
54  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
55  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
56  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
57  * THE POSSIBILITY OF SUCH DAMAGE.
58  */
59 package jdk.internal.org.objectweb.asm;
60 
61 /**
62  * A dynamically extensible vector of bytes. This class is roughly equivalent to a DataOutputStream
63  * on top of a ByteArrayOutputStream, but is more efficient.
64  *
65  * @author Eric Bruneton
66  */
67 public class ByteVector {
68 
69     /** The content of this vector. Only the first {@link #length} bytes contain real data. */
70     byte[] data;
71 
72     /** The actual number of bytes in this vector. */
73     int length;
74 
75     /** Constructs a new {@link ByteVector} with a default initial capacity. */
ByteVector()76     public ByteVector() {
77         data = new byte[64];
78     }
79 
80     /**
81       * Constructs a new {@link ByteVector} with the given initial capacity.
82       *
83       * @param initialCapacity the initial capacity of the byte vector to be constructed.
84       */
ByteVector(final int initialCapacity)85     public ByteVector(final int initialCapacity) {
86         data = new byte[initialCapacity];
87     }
88 
89     /**
90       * Constructs a new {@link ByteVector} from the given initial data.
91       *
92       * @param data the initial data of the new byte vector.
93       */
ByteVector(final byte[] data)94     ByteVector(final byte[] data) {
95         this.data = data;
96         this.length = data.length;
97     }
98 
99     /**
100       * Puts a byte into this byte vector. The byte vector is automatically enlarged if necessary.
101       *
102       * @param byteValue a byte.
103       * @return this byte vector.
104       */
putByte(final int byteValue)105     public ByteVector putByte(final int byteValue) {
106         int currentLength = length;
107         if (currentLength + 1 > data.length) {
108             enlarge(1);
109         }
110         data[currentLength++] = (byte) byteValue;
111         length = currentLength;
112         return this;
113     }
114 
115     /**
116       * Puts two bytes into this byte vector. The byte vector is automatically enlarged if necessary.
117       *
118       * @param byteValue1 a byte.
119       * @param byteValue2 another byte.
120       * @return this byte vector.
121       */
put11(final int byteValue1, final int byteValue2)122     final ByteVector put11(final int byteValue1, final int byteValue2) {
123         int currentLength = length;
124         if (currentLength + 2 > data.length) {
125             enlarge(2);
126         }
127         byte[] currentData = data;
128         currentData[currentLength++] = (byte) byteValue1;
129         currentData[currentLength++] = (byte) byteValue2;
130         length = currentLength;
131         return this;
132     }
133 
134     /**
135       * Puts a short into this byte vector. The byte vector is automatically enlarged if necessary.
136       *
137       * @param shortValue a short.
138       * @return this byte vector.
139       */
putShort(final int shortValue)140     public ByteVector putShort(final int shortValue) {
141         int currentLength = length;
142         if (currentLength + 2 > data.length) {
143             enlarge(2);
144         }
145         byte[] currentData = data;
146         currentData[currentLength++] = (byte) (shortValue >>> 8);
147         currentData[currentLength++] = (byte) shortValue;
148         length = currentLength;
149         return this;
150     }
151 
152     /**
153       * Puts a byte and a short into this byte vector. The byte vector is automatically enlarged if
154       * necessary.
155       *
156       * @param byteValue a byte.
157       * @param shortValue a short.
158       * @return this byte vector.
159       */
put12(final int byteValue, final int shortValue)160     final ByteVector put12(final int byteValue, final int shortValue) {
161         int currentLength = length;
162         if (currentLength + 3 > data.length) {
163             enlarge(3);
164         }
165         byte[] currentData = data;
166         currentData[currentLength++] = (byte) byteValue;
167         currentData[currentLength++] = (byte) (shortValue >>> 8);
168         currentData[currentLength++] = (byte) shortValue;
169         length = currentLength;
170         return this;
171     }
172 
173     /**
174       * Puts two bytes and a short into this byte vector. The byte vector is automatically enlarged if
175       * necessary.
176       *
177       * @param byteValue1 a byte.
178       * @param byteValue2 another byte.
179       * @param shortValue a short.
180       * @return this byte vector.
181       */
put112(final int byteValue1, final int byteValue2, final int shortValue)182     final ByteVector put112(final int byteValue1, final int byteValue2, final int shortValue) {
183         int currentLength = length;
184         if (currentLength + 4 > data.length) {
185             enlarge(4);
186         }
187         byte[] currentData = data;
188         currentData[currentLength++] = (byte) byteValue1;
189         currentData[currentLength++] = (byte) byteValue2;
190         currentData[currentLength++] = (byte) (shortValue >>> 8);
191         currentData[currentLength++] = (byte) shortValue;
192         length = currentLength;
193         return this;
194     }
195 
196     /**
197       * Puts an int into this byte vector. The byte vector is automatically enlarged if necessary.
198       *
199       * @param intValue an int.
200       * @return this byte vector.
201       */
putInt(final int intValue)202     public ByteVector putInt(final int intValue) {
203         int currentLength = length;
204         if (currentLength + 4 > data.length) {
205             enlarge(4);
206         }
207         byte[] currentData = data;
208         currentData[currentLength++] = (byte) (intValue >>> 24);
209         currentData[currentLength++] = (byte) (intValue >>> 16);
210         currentData[currentLength++] = (byte) (intValue >>> 8);
211         currentData[currentLength++] = (byte) intValue;
212         length = currentLength;
213         return this;
214     }
215 
216     /**
217       * Puts one byte and two shorts into this byte vector. The byte vector is automatically enlarged
218       * if necessary.
219       *
220       * @param byteValue a byte.
221       * @param shortValue1 a short.
222       * @param shortValue2 another short.
223       * @return this byte vector.
224       */
put122(final int byteValue, final int shortValue1, final int shortValue2)225     final ByteVector put122(final int byteValue, final int shortValue1, final int shortValue2) {
226         int currentLength = length;
227         if (currentLength + 5 > data.length) {
228             enlarge(5);
229         }
230         byte[] currentData = data;
231         currentData[currentLength++] = (byte) byteValue;
232         currentData[currentLength++] = (byte) (shortValue1 >>> 8);
233         currentData[currentLength++] = (byte) shortValue1;
234         currentData[currentLength++] = (byte) (shortValue2 >>> 8);
235         currentData[currentLength++] = (byte) shortValue2;
236         length = currentLength;
237         return this;
238     }
239 
240     /**
241       * Puts a long into this byte vector. The byte vector is automatically enlarged if necessary.
242       *
243       * @param longValue a long.
244       * @return this byte vector.
245       */
putLong(final long longValue)246     public ByteVector putLong(final long longValue) {
247         int currentLength = length;
248         if (currentLength + 8 > data.length) {
249             enlarge(8);
250         }
251         byte[] currentData = data;
252         int intValue = (int) (longValue >>> 32);
253         currentData[currentLength++] = (byte) (intValue >>> 24);
254         currentData[currentLength++] = (byte) (intValue >>> 16);
255         currentData[currentLength++] = (byte) (intValue >>> 8);
256         currentData[currentLength++] = (byte) intValue;
257         intValue = (int) longValue;
258         currentData[currentLength++] = (byte) (intValue >>> 24);
259         currentData[currentLength++] = (byte) (intValue >>> 16);
260         currentData[currentLength++] = (byte) (intValue >>> 8);
261         currentData[currentLength++] = (byte) intValue;
262         length = currentLength;
263         return this;
264     }
265 
266     /**
267       * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if
268       * necessary.
269       *
270       * @param stringValue a String whose UTF8 encoded length must be less than 65536.
271       * @return this byte vector.
272       */
273     // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
putUTF8(final String stringValue)274     public ByteVector putUTF8(final String stringValue) {
275         int charLength = stringValue.length();
276         if (charLength > 65535) {
277             throw new IllegalArgumentException("UTF8 string too large");
278         }
279         int currentLength = length;
280         if (currentLength + 2 + charLength > data.length) {
281             enlarge(2 + charLength);
282         }
283         byte[] currentData = data;
284         // Optimistic algorithm: instead of computing the byte length and then serializing the string
285         // (which requires two loops), we assume the byte length is equal to char length (which is the
286         // most frequent case), and we start serializing the string right away. During the
287         // serialization, if we find that this assumption is wrong, we continue with the general method.
288         currentData[currentLength++] = (byte) (charLength >>> 8);
289         currentData[currentLength++] = (byte) charLength;
290         for (int i = 0; i < charLength; ++i) {
291             char charValue = stringValue.charAt(i);
292             if (charValue >= '\u0001' && charValue <= '\u007F') {
293                 currentData[currentLength++] = (byte) charValue;
294             } else {
295                 length = currentLength;
296                 return encodeUtf8(stringValue, i, 65535);
297             }
298         }
299         length = currentLength;
300         return this;
301     }
302 
303     /**
304       * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if
305       * necessary. The string length is encoded in two bytes before the encoded characters, if there is
306       * space for that (i.e. if this.length - offset - 2 &gt;= 0).
307       *
308       * @param stringValue the String to encode.
309       * @param offset the index of the first character to encode. The previous characters are supposed
310       *     to have already been encoded, using only one byte per character.
311       * @param maxByteLength the maximum byte length of the encoded string, including the already
312       *     encoded characters.
313       * @return this byte vector.
314       */
encodeUtf8(final String stringValue, final int offset, final int maxByteLength)315     final ByteVector encodeUtf8(final String stringValue, final int offset, final int maxByteLength) {
316         int charLength = stringValue.length();
317         int byteLength = offset;
318         for (int i = offset; i < charLength; ++i) {
319             char charValue = stringValue.charAt(i);
320             if (charValue >= 0x0001 && charValue <= 0x007F) {
321                 byteLength++;
322             } else if (charValue <= 0x07FF) {
323                 byteLength += 2;
324             } else {
325                 byteLength += 3;
326             }
327         }
328         if (byteLength > maxByteLength) {
329             throw new IllegalArgumentException("UTF8 string too large");
330         }
331         // Compute where 'byteLength' must be stored in 'data', and store it at this location.
332         int byteLengthOffset = length - offset - 2;
333         if (byteLengthOffset >= 0) {
334             data[byteLengthOffset] = (byte) (byteLength >>> 8);
335             data[byteLengthOffset + 1] = (byte) byteLength;
336         }
337         if (length + byteLength - offset > data.length) {
338             enlarge(byteLength - offset);
339         }
340         int currentLength = length;
341         for (int i = offset; i < charLength; ++i) {
342             char charValue = stringValue.charAt(i);
343             if (charValue >= 0x0001 && charValue <= 0x007F) {
344                 data[currentLength++] = (byte) charValue;
345             } else if (charValue <= 0x07FF) {
346                 data[currentLength++] = (byte) (0xC0 | charValue >> 6 & 0x1F);
347                 data[currentLength++] = (byte) (0x80 | charValue & 0x3F);
348             } else {
349                 data[currentLength++] = (byte) (0xE0 | charValue >> 12 & 0xF);
350                 data[currentLength++] = (byte) (0x80 | charValue >> 6 & 0x3F);
351                 data[currentLength++] = (byte) (0x80 | charValue & 0x3F);
352             }
353         }
354         length = currentLength;
355         return this;
356     }
357 
358     /**
359       * Puts an array of bytes into this byte vector. The byte vector is automatically enlarged if
360       * necessary.
361       *
362       * @param byteArrayValue an array of bytes. May be {@literal null} to put {@code byteLength} null
363       *     bytes into this byte vector.
364       * @param byteOffset index of the first byte of byteArrayValue that must be copied.
365       * @param byteLength number of bytes of byteArrayValue that must be copied.
366       * @return this byte vector.
367       */
putByteArray( final byte[] byteArrayValue, final int byteOffset, final int byteLength)368     public ByteVector putByteArray(
369             final byte[] byteArrayValue, final int byteOffset, final int byteLength) {
370         if (length + byteLength > data.length) {
371             enlarge(byteLength);
372         }
373         if (byteArrayValue != null) {
374             System.arraycopy(byteArrayValue, byteOffset, data, length, byteLength);
375         }
376         length += byteLength;
377         return this;
378     }
379 
380     /**
381       * Enlarges this byte vector so that it can receive 'size' more bytes.
382       *
383       * @param size number of additional bytes that this byte vector should be able to receive.
384       */
enlarge(final int size)385     private void enlarge(final int size) {
386         int doubleCapacity = 2 * data.length;
387         int minimalCapacity = length + size;
388         byte[] newData = new byte[doubleCapacity > minimalCapacity ? doubleCapacity : minimalCapacity];
389         System.arraycopy(data, 0, newData, 0, length);
390         data = newData;
391     }
392 }
393