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