001// ASM: a very small and fast Java bytecode manipulation framework
002// Copyright (c) 2000-2011 INRIA, France Telecom
003// All rights reserved.
004//
005// Redistribution and use in source and binary forms, with or without
006// modification, are permitted provided that the following conditions
007// are met:
008// 1. Redistributions of source code must retain the above copyright
009//    notice, this list of conditions and the following disclaimer.
010// 2. Redistributions in binary form must reproduce the above copyright
011//    notice, this list of conditions and the following disclaimer in the
012//    documentation and/or other materials provided with the distribution.
013// 3. Neither the name of the copyright holders nor the names of its
014//    contributors may be used to endorse or promote products derived from
015//    this software without specific prior written permission.
016//
017// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
018// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
019// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
020// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
021// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
022// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
023// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
024// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
025// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
026// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
027// THE POSSIBILITY OF SUCH DAMAGE.
028package io.ebean.enhance.asm;
029
030/**
031 * A dynamically extensible vector of bytes. This class is roughly equivalent to a DataOutputStream
032 * on top of a ByteArrayOutputStream, but is more efficient.
033 *
034 * @author Eric Bruneton
035 */
036public class ByteVector {
037
038  /** The content of this vector. Only the first {@link #length} bytes contain real data. */
039  byte[] data;
040
041  /** The actual number of bytes in this vector. */
042  int length;
043
044  /** Constructs a new {@link ByteVector} with a default initial capacity. */
045  public ByteVector() {
046    data = new byte[64];
047  }
048
049  /**
050   * Constructs a new {@link ByteVector} with the given initial capacity.
051   *
052   * @param initialCapacity the initial capacity of the byte vector to be constructed.
053   */
054  public ByteVector(final int initialCapacity) {
055    data = new byte[initialCapacity];
056  }
057
058  /**
059   * Constructs a new {@link ByteVector} from the given initial data.
060   *
061   * @param data the initial data of the new byte vector.
062   */
063  ByteVector(final byte[] data) {
064    this.data = data;
065    this.length = data.length;
066  }
067
068  /**
069   * Returns the actual number of bytes in this vector.
070   *
071   * @return the actual number of bytes in this vector.
072   */
073  public int size() {
074    return length;
075  }
076
077  /**
078   * Puts a byte into this byte vector. The byte vector is automatically enlarged if necessary.
079   *
080   * @param byteValue a byte.
081   * @return this byte vector.
082   */
083  public ByteVector putByte(final int byteValue) {
084    int currentLength = length;
085    if (currentLength + 1 > data.length) {
086      enlarge(1);
087    }
088    data[currentLength++] = (byte) byteValue;
089    length = currentLength;
090    return this;
091  }
092
093  /**
094   * Puts two bytes into this byte vector. The byte vector is automatically enlarged if necessary.
095   *
096   * @param byteValue1 a byte.
097   * @param byteValue2 another byte.
098   * @return this byte vector.
099   */
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   */
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   */
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   */
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   */
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   */
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   */
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).
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   */
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   */
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   */
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}