1/***
2 * ASM: a very small and fast Java bytecode manipulation framework
3 * Copyright (c) 2000-2007 INRIA, France Telecom
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the copyright holders nor the names of its
15 *    contributors may be used to endorse or promote products derived from
16 *    this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28 * THE POSSIBILITY OF SUCH DAMAGE.
29 */
30package org.mockito.asm;
31
32/**
33 * A dynamically extensible vector of bytes. This class is roughly equivalent to
34 * a DataOutputStream on top of a ByteArrayOutputStream, but is more efficient.
35 *
36 * @author Eric Bruneton
37 */
38public class ByteVector {
39
40    /**
41     * The content of this vector.
42     */
43    byte[] data;
44
45    /**
46     * Actual number of bytes in this vector.
47     */
48    int length;
49
50    /**
51     * Constructs a new {@link ByteVector ByteVector} with a default initial
52     * size.
53     */
54    public ByteVector() {
55        data = new byte[64];
56    }
57
58    /**
59     * Constructs a new {@link ByteVector ByteVector} with the given initial
60     * size.
61     *
62     * @param initialSize the initial size of the byte vector to be constructed.
63     */
64    public ByteVector(final int initialSize) {
65        data = new byte[initialSize];
66    }
67
68    /**
69     * Puts a byte into this byte vector. The byte vector is automatically
70     * enlarged if necessary.
71     *
72     * @param b a byte.
73     * @return this byte vector.
74     */
75    public ByteVector putByte(final int b) {
76        int length = this.length;
77        if (length + 1 > data.length) {
78            enlarge(1);
79        }
80        data[length++] = (byte) b;
81        this.length = length;
82        return this;
83    }
84
85    /**
86     * Puts two bytes into this byte vector. The byte vector is automatically
87     * enlarged if necessary.
88     *
89     * @param b1 a byte.
90     * @param b2 another byte.
91     * @return this byte vector.
92     */
93    ByteVector put11(final int b1, final int b2) {
94        int length = this.length;
95        if (length + 2 > data.length) {
96            enlarge(2);
97        }
98        byte[] data = this.data;
99        data[length++] = (byte) b1;
100        data[length++] = (byte) b2;
101        this.length = length;
102        return this;
103    }
104
105    /**
106     * Puts a short into this byte vector. The byte vector is automatically
107     * enlarged if necessary.
108     *
109     * @param s a short.
110     * @return this byte vector.
111     */
112    public ByteVector putShort(final int s) {
113        int length = this.length;
114        if (length + 2 > data.length) {
115            enlarge(2);
116        }
117        byte[] data = this.data;
118        data[length++] = (byte) (s >>> 8);
119        data[length++] = (byte) s;
120        this.length = length;
121        return this;
122    }
123
124    /**
125     * Puts a byte and a short into this byte vector. The byte vector is
126     * automatically enlarged if necessary.
127     *
128     * @param b a byte.
129     * @param s a short.
130     * @return this byte vector.
131     */
132    ByteVector put12(final int b, final int s) {
133        int length = this.length;
134        if (length + 3 > data.length) {
135            enlarge(3);
136        }
137        byte[] data = this.data;
138        data[length++] = (byte) b;
139        data[length++] = (byte) (s >>> 8);
140        data[length++] = (byte) s;
141        this.length = length;
142        return this;
143    }
144
145    /**
146     * Puts an int into this byte vector. The byte vector is automatically
147     * enlarged if necessary.
148     *
149     * @param i an int.
150     * @return this byte vector.
151     */
152    public ByteVector putInt(final int i) {
153        int length = this.length;
154        if (length + 4 > data.length) {
155            enlarge(4);
156        }
157        byte[] data = this.data;
158        data[length++] = (byte) (i >>> 24);
159        data[length++] = (byte) (i >>> 16);
160        data[length++] = (byte) (i >>> 8);
161        data[length++] = (byte) i;
162        this.length = length;
163        return this;
164    }
165
166    /**
167     * Puts a long into this byte vector. The byte vector is automatically
168     * enlarged if necessary.
169     *
170     * @param l a long.
171     * @return this byte vector.
172     */
173    public ByteVector putLong(final long l) {
174        int length = this.length;
175        if (length + 8 > data.length) {
176            enlarge(8);
177        }
178        byte[] data = this.data;
179        int i = (int) (l >>> 32);
180        data[length++] = (byte) (i >>> 24);
181        data[length++] = (byte) (i >>> 16);
182        data[length++] = (byte) (i >>> 8);
183        data[length++] = (byte) i;
184        i = (int) l;
185        data[length++] = (byte) (i >>> 24);
186        data[length++] = (byte) (i >>> 16);
187        data[length++] = (byte) (i >>> 8);
188        data[length++] = (byte) i;
189        this.length = length;
190        return this;
191    }
192
193    /**
194     * Puts an UTF8 string into this byte vector. The byte vector is
195     * automatically enlarged if necessary.
196     *
197     * @param s a String.
198     * @return this byte vector.
199     */
200    public ByteVector putUTF8(final String s) {
201        int charLength = s.length();
202        if (length + 2 + charLength > data.length) {
203            enlarge(2 + charLength);
204        }
205        int len = length;
206        byte[] data = this.data;
207        // optimistic algorithm: instead of computing the byte length and then
208        // serializing the string (which requires two loops), we assume the byte
209        // length is equal to char length (which is the most frequent case), and
210        // we start serializing the string right away. During the serialization,
211        // if we find that this assumption is wrong, we continue with the
212        // general method.
213        data[len++] = (byte) (charLength >>> 8);
214        data[len++] = (byte) charLength;
215        for (int i = 0; i < charLength; ++i) {
216            char c = s.charAt(i);
217            if (c >= '\001' && c <= '\177') {
218                data[len++] = (byte) c;
219            } else {
220                int byteLength = i;
221                for (int j = i; j < charLength; ++j) {
222                    c = s.charAt(j);
223                    if (c >= '\001' && c <= '\177') {
224                        byteLength++;
225                    } else if (c > '\u07FF') {
226                        byteLength += 3;
227                    } else {
228                        byteLength += 2;
229                    }
230                }
231                data[length] = (byte) (byteLength >>> 8);
232                data[length + 1] = (byte) byteLength;
233                if (length + 2 + byteLength > data.length) {
234                    length = len;
235                    enlarge(2 + byteLength);
236                    data = this.data;
237                }
238                for (int j = i; j < charLength; ++j) {
239                    c = s.charAt(j);
240                    if (c >= '\001' && c <= '\177') {
241                        data[len++] = (byte) c;
242                    } else if (c > '\u07FF') {
243                        data[len++] = (byte) (0xE0 | c >> 12 & 0xF);
244                        data[len++] = (byte) (0x80 | c >> 6 & 0x3F);
245                        data[len++] = (byte) (0x80 | c & 0x3F);
246                    } else {
247                        data[len++] = (byte) (0xC0 | c >> 6 & 0x1F);
248                        data[len++] = (byte) (0x80 | c & 0x3F);
249                    }
250                }
251                break;
252            }
253        }
254        length = len;
255        return this;
256    }
257
258    /**
259     * Puts an array of bytes into this byte vector. The byte vector is
260     * automatically enlarged if necessary.
261     *
262     * @param b an array of bytes. May be <tt>null</tt> to put <tt>len</tt>
263     *        null bytes into this byte vector.
264     * @param off index of the fist byte of b that must be copied.
265     * @param len number of bytes of b that must be copied.
266     * @return this byte vector.
267     */
268    public ByteVector putByteArray(final byte[] b, final int off, final int len)
269    {
270        if (length + len > data.length) {
271            enlarge(len);
272        }
273        if (b != null) {
274            System.arraycopy(b, off, data, length, len);
275        }
276        length += len;
277        return this;
278    }
279
280    /**
281     * Enlarge this byte vector so that it can receive n more bytes.
282     *
283     * @param size number of additional bytes that this byte vector should be
284     *        able to receive.
285     */
286    private void enlarge(final int size) {
287        int length1 = 2 * data.length;
288        int length2 = length + size;
289        byte[] newData = new byte[length1 > length2 ? length1 : length2];
290        System.arraycopy(data, 0, newData, 0, length);
291        data = newData;
292    }
293}
294