001/***
002 * ASM: a very small and fast Java bytecode manipulation framework
003 * Copyright (c) 2000-2011 INRIA, France Telecom
004 * All rights reserved.
005 *
006 * Redistribution and use in source and binary forms, with or without
007 * modification, are permitted provided that the following conditions
008 * are met:
009 * 1. Redistributions of source code must retain the above copyright
010 *    notice, this list of conditions and the following disclaimer.
011 * 2. Redistributions in binary form must reproduce the above copyright
012 *    notice, this list of conditions and the following disclaimer in the
013 *    documentation and/or other materials provided with the distribution.
014 * 3. Neither the name of the copyright holders nor the names of its
015 *    contributors may be used to endorse or promote products derived from
016 *    this software without specific prior written permission.
017 *
018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
022 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
028 * THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package org.springframework.asm;
031
032/**
033 * A dynamically extensible vector of bytes. This class is roughly equivalent to
034 * a DataOutputStream on top of a ByteArrayOutputStream, but is more efficient.
035 * 
036 * @author Eric Bruneton
037 */
038public class ByteVector {
039
040    /**
041     * The content of this vector.
042     */
043    byte[] data;
044
045    /**
046     * Actual number of bytes in this vector.
047     */
048    int length;
049
050    /**
051     * Constructs a new {@link ByteVector ByteVector} with a default initial
052     * size.
053     */
054    public ByteVector() {
055        data = new byte[64];
056    }
057
058    /**
059     * Constructs a new {@link ByteVector ByteVector} with the given initial
060     * size.
061     * 
062     * @param initialSize
063     *            the initial size of the byte vector to be constructed.
064     */
065    public ByteVector(final int initialSize) {
066        data = new byte[initialSize];
067    }
068
069    /**
070     * Puts a byte into this byte vector. The byte vector is automatically
071     * enlarged if necessary.
072     * 
073     * @param b
074     *            a byte.
075     * @return this byte vector.
076     */
077    public ByteVector putByte(final int b) {
078        int length = this.length;
079        if (length + 1 > data.length) {
080            enlarge(1);
081        }
082        data[length++] = (byte) b;
083        this.length = length;
084        return this;
085    }
086
087    /**
088     * Puts two bytes into this byte vector. The byte vector is automatically
089     * enlarged if necessary.
090     * 
091     * @param b1
092     *            a byte.
093     * @param b2
094     *            another byte.
095     * @return this byte vector.
096     */
097    ByteVector put11(final int b1, final int b2) {
098        int length = this.length;
099        if (length + 2 > data.length) {
100            enlarge(2);
101        }
102        byte[] data = this.data;
103        data[length++] = (byte) b1;
104        data[length++] = (byte) b2;
105        this.length = length;
106        return this;
107    }
108
109    /**
110     * Puts a short into this byte vector. The byte vector is automatically
111     * enlarged if necessary.
112     * 
113     * @param s
114     *            a short.
115     * @return this byte vector.
116     */
117    public ByteVector putShort(final int s) {
118        int length = this.length;
119        if (length + 2 > data.length) {
120            enlarge(2);
121        }
122        byte[] data = this.data;
123        data[length++] = (byte) (s >>> 8);
124        data[length++] = (byte) s;
125        this.length = length;
126        return this;
127    }
128
129    /**
130     * Puts a byte and a short into this byte vector. The byte vector is
131     * automatically enlarged if necessary.
132     * 
133     * @param b
134     *            a byte.
135     * @param s
136     *            a short.
137     * @return this byte vector.
138     */
139    ByteVector put12(final int b, final int s) {
140        int length = this.length;
141        if (length + 3 > data.length) {
142            enlarge(3);
143        }
144        byte[] data = this.data;
145        data[length++] = (byte) b;
146        data[length++] = (byte) (s >>> 8);
147        data[length++] = (byte) s;
148        this.length = length;
149        return this;
150    }
151
152    /**
153     * Puts an int into this byte vector. The byte vector is automatically
154     * enlarged if necessary.
155     * 
156     * @param i
157     *            an int.
158     * @return this byte vector.
159     */
160    public ByteVector putInt(final int i) {
161        int length = this.length;
162        if (length + 4 > data.length) {
163            enlarge(4);
164        }
165        byte[] data = this.data;
166        data[length++] = (byte) (i >>> 24);
167        data[length++] = (byte) (i >>> 16);
168        data[length++] = (byte) (i >>> 8);
169        data[length++] = (byte) i;
170        this.length = length;
171        return this;
172    }
173
174    /**
175     * Puts a long into this byte vector. The byte vector is automatically
176     * enlarged if necessary.
177     * 
178     * @param l
179     *            a long.
180     * @return this byte vector.
181     */
182    public ByteVector putLong(final long l) {
183        int length = this.length;
184        if (length + 8 > data.length) {
185            enlarge(8);
186        }
187        byte[] data = this.data;
188        int i = (int) (l >>> 32);
189        data[length++] = (byte) (i >>> 24);
190        data[length++] = (byte) (i >>> 16);
191        data[length++] = (byte) (i >>> 8);
192        data[length++] = (byte) i;
193        i = (int) l;
194        data[length++] = (byte) (i >>> 24);
195        data[length++] = (byte) (i >>> 16);
196        data[length++] = (byte) (i >>> 8);
197        data[length++] = (byte) i;
198        this.length = length;
199        return this;
200    }
201
202    /**
203     * Puts an UTF8 string into this byte vector. The byte vector is
204     * automatically enlarged if necessary.
205     * 
206     * @param s
207     *            a String whose UTF8 encoded length must be less than 65536.
208     * @return this byte vector.
209     */
210    public ByteVector putUTF8(final String s) {
211        int charLength = s.length();
212        if (charLength > 65535) {
213            throw new IllegalArgumentException();
214        }
215        int len = length;
216        if (len + 2 + charLength > data.length) {
217            enlarge(2 + charLength);
218        }
219        byte[] data = this.data;
220        // optimistic algorithm: instead of computing the byte length and then
221        // serializing the string (which requires two loops), we assume the byte
222        // length is equal to char length (which is the most frequent case), and
223        // we start serializing the string right away. During the serialization,
224        // if we find that this assumption is wrong, we continue with the
225        // general method.
226        data[len++] = (byte) (charLength >>> 8);
227        data[len++] = (byte) charLength;
228        for (int i = 0; i < charLength; ++i) {
229            char c = s.charAt(i);
230            if (c >= '\001' && c <= '\177') {
231                data[len++] = (byte) c;
232            } else {
233                length = len;
234                return encodeUTF8(s, i, 65535);
235            }
236        }
237        length = len;
238        return this;
239    }
240
241    /**
242     * Puts an UTF8 string into this byte vector. The byte vector is
243     * automatically enlarged if necessary. The string length is encoded in two
244     * bytes before the encoded characters, if there is space for that (i.e. if
245     * this.length - i - 2 >= 0).
246     * 
247     * @param s
248     *            the String to encode.
249     * @param i
250     *            the index of the first character to encode. The previous
251     *            characters are supposed to have already been encoded, using
252     *            only one byte per character.
253     * @param maxByteLength
254     *            the maximum byte length of the encoded string, including the
255     *            already encoded characters.
256     * @return this byte vector.
257     */
258    ByteVector encodeUTF8(final String s, int i, int maxByteLength) {
259        int charLength = s.length();
260        int byteLength = i;
261        char c;
262        for (int j = i; j < charLength; ++j) {
263            c = s.charAt(j);
264            if (c >= '\001' && c <= '\177') {
265                byteLength++;
266            } else if (c > '\u07FF') {
267                byteLength += 3;
268            } else {
269                byteLength += 2;
270            }
271        }
272        if (byteLength > maxByteLength) {
273            throw new IllegalArgumentException();
274        }
275        int start = length - i - 2;
276        if (start >= 0) {
277          data[start] = (byte) (byteLength >>> 8);
278          data[start + 1] = (byte) byteLength;
279        }
280        if (length + byteLength - i > data.length) {
281            enlarge(byteLength - i);
282        }
283        int len = length;
284        for (int j = i; j < charLength; ++j) {
285            c = s.charAt(j);
286            if (c >= '\001' && c <= '\177') {
287                data[len++] = (byte) c;
288            } else if (c > '\u07FF') {
289                data[len++] = (byte) (0xE0 | c >> 12 & 0xF);
290                data[len++] = (byte) (0x80 | c >> 6 & 0x3F);
291                data[len++] = (byte) (0x80 | c & 0x3F);
292            } else {
293                data[len++] = (byte) (0xC0 | c >> 6 & 0x1F);
294                data[len++] = (byte) (0x80 | c & 0x3F);
295            }
296        }
297        length = len;
298        return this;
299    }
300
301    /**
302     * Puts an array of bytes into this byte vector. The byte vector is
303     * automatically enlarged if necessary.
304     * 
305     * @param b
306     *            an array of bytes. May be <tt>null</tt> to put <tt>len</tt>
307     *            null bytes into this byte vector.
308     * @param off
309     *            index of the fist byte of b that must be copied.
310     * @param len
311     *            number of bytes of b that must be copied.
312     * @return this byte vector.
313     */
314    public ByteVector putByteArray(final byte[] b, final int off, final int len) {
315        if (length + len > data.length) {
316            enlarge(len);
317        }
318        if (b != null) {
319            System.arraycopy(b, off, data, length, len);
320        }
321        length += len;
322        return this;
323    }
324
325    /**
326     * Enlarge this byte vector so that it can receive n more bytes.
327     * 
328     * @param size
329     *            number of additional bytes that this byte vector should be
330     *            able to receive.
331     */
332    private void enlarge(final int size) {
333        int length1 = 2 * data.length;
334        int length2 = length + size;
335        byte[] newData = new byte[length1 > length2 ? length1 : length2];
336        System.arraycopy(data, 0, newData, 0, length);
337        data = newData;
338    }
339}