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