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