Home | History | Annotate | Download | only in asm
      1 /***
      2  * ASM: a very small and fast Java bytecode manipulation framework
      3  * Copyright (c) 2000-2005 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  */
     30 package org.objectweb.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  */
     38 public 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