Home | History | Annotate | Download | only in bytecode
      1 /*
      2  * Javassist, a Java-bytecode translator toolkit.
      3  * Copyright (C) 1999-2010 Shigeru Chiba. All Rights Reserved.
      4  *
      5  * The contents of this file are subject to the Mozilla Public License Version
      6  * 1.1 (the "License"); you may not use this file except in compliance with
      7  * the License.  Alternatively, the contents of this file may be used under
      8  * the terms of the GNU Lesser General Public License Version 2.1 or later.
      9  *
     10  * Software distributed under the License is distributed on an "AS IS" basis,
     11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
     12  * for the specific language governing rights and limitations under the
     13  * License.
     14  */
     15 
     16 package javassist.bytecode;
     17 
     18 import java.io.OutputStream;
     19 import java.io.IOException;
     20 
     21 final class ByteStream extends OutputStream {
     22     private byte[] buf;
     23     private int count;
     24 
     25     public ByteStream() { this(32); }
     26 
     27     public ByteStream(int size) {
     28         buf = new byte[size];
     29         count = 0;
     30     }
     31 
     32     public int getPos() { return count; }
     33     public int size() { return count; }
     34 
     35     public void writeBlank(int len) {
     36         enlarge(len);
     37         count += len;
     38     }
     39 
     40     public void write(byte[] data) {
     41         write(data, 0, data.length);
     42     }
     43 
     44     public void write(byte[] data, int off, int len) {
     45         enlarge(len);
     46         System.arraycopy(data, off, buf, count, len);
     47         count += len;
     48     }
     49 
     50     public void write(int b) {
     51         enlarge(1);
     52         int oldCount = count;
     53         buf[oldCount] = (byte)b;
     54         count = oldCount + 1;
     55     }
     56 
     57     public void writeShort(int s) {
     58         enlarge(2);
     59         int oldCount = count;
     60         buf[oldCount] = (byte)(s >>> 8);
     61         buf[oldCount + 1] = (byte)s;
     62         count = oldCount + 2;
     63     }
     64 
     65     public void writeInt(int i) {
     66         enlarge(4);
     67         int oldCount = count;
     68         buf[oldCount] = (byte)(i >>> 24);
     69         buf[oldCount + 1] = (byte)(i >>> 16);
     70         buf[oldCount + 2] = (byte)(i >>> 8);
     71         buf[oldCount + 3] = (byte)i;
     72         count = oldCount + 4;
     73     }
     74 
     75     public void writeLong(long i) {
     76         enlarge(8);
     77         int oldCount = count;
     78         buf[oldCount] = (byte)(i >>> 56);
     79         buf[oldCount + 1] = (byte)(i >>> 48);
     80         buf[oldCount + 2] = (byte)(i >>> 40);
     81         buf[oldCount + 3] = (byte)(i >>> 32);
     82         buf[oldCount + 4] = (byte)(i >>> 24);
     83         buf[oldCount + 5] = (byte)(i >>> 16);
     84         buf[oldCount + 6] = (byte)(i >>> 8);
     85         buf[oldCount + 7] = (byte)i;
     86         count = oldCount + 8;
     87     }
     88 
     89     public void writeFloat(float v) {
     90         writeInt(Float.floatToIntBits(v));
     91     }
     92 
     93     public void writeDouble(double v) {
     94         writeLong(Double.doubleToLongBits(v));
     95     }
     96 
     97     public void writeUTF(String s) {
     98         int sLen = s.length();
     99         int pos = count;
    100         enlarge(sLen + 2);
    101 
    102         byte[] buffer = buf;
    103         buffer[pos++] = (byte)(sLen >>> 8);
    104         buffer[pos++] = (byte)sLen;
    105         for (int i = 0; i < sLen; ++i) {
    106             char c = s.charAt(i);
    107             if (0x01 <= c && c <= 0x7f)
    108                 buffer[pos++] = (byte)c;
    109             else {
    110                 writeUTF2(s, sLen, i);
    111                 return;
    112             }
    113         }
    114 
    115         count = pos;
    116     }
    117 
    118     private void writeUTF2(String s, int sLen, int offset) {
    119         int size = sLen;
    120         for (int i = offset; i < sLen; i++) {
    121             int c = s.charAt(i);
    122             if (c > 0x7ff)
    123                 size += 2;  // 3 bytes code
    124             else if (c == 0 || c > 0x7f)
    125                 ++size;     // 2 bytes code
    126         }
    127 
    128         if (size > 65535)
    129             throw new RuntimeException(
    130                     "encoded string too long: " + sLen + size + " bytes");
    131 
    132         enlarge(size + 2);
    133         int pos = count;
    134         byte[] buffer = buf;
    135         buffer[pos] = (byte)(size >>> 8);
    136         buffer[pos + 1] = (byte)size;
    137         pos += 2 + offset;
    138         for (int j = offset; j < sLen; ++j) {
    139             int c = s.charAt(j);
    140             if (0x01 <= c && c <= 0x7f)
    141                 buffer[pos++] = (byte) c;
    142             else if (c > 0x07ff) {
    143                 buffer[pos] = (byte)(0xe0 | ((c >> 12) & 0x0f));
    144                 buffer[pos + 1] = (byte)(0x80 | ((c >> 6) & 0x3f));
    145                 buffer[pos + 2] = (byte)(0x80 | (c & 0x3f));
    146                 pos += 3;
    147             }
    148             else {
    149                 buffer[pos] = (byte)(0xc0 | ((c >> 6) & 0x1f));
    150                 buffer[pos + 1] = (byte)(0x80 | (c & 0x3f));
    151                 pos += 2;
    152             }
    153         }
    154 
    155         count = pos;
    156     }
    157 
    158     public void write(int pos, int value) {
    159         buf[pos] = (byte)value;
    160     }
    161 
    162     public void writeShort(int pos, int value) {
    163         buf[pos] = (byte)(value >>> 8);
    164         buf[pos + 1] = (byte)value;
    165     }
    166 
    167     public void writeInt(int pos, int value) {
    168         buf[pos] = (byte)(value >>> 24);
    169         buf[pos + 1] = (byte)(value >>> 16);
    170         buf[pos + 2] = (byte)(value >>> 8);
    171         buf[pos + 3] = (byte)value;
    172     }
    173 
    174     public byte[] toByteArray() {
    175         byte[] buf2 = new byte[count];
    176         System.arraycopy(buf, 0, buf2, 0, count);
    177         return buf2;
    178     }
    179 
    180     public void writeTo(OutputStream out) throws IOException {
    181         out.write(buf, 0, count);
    182     }
    183 
    184     public void enlarge(int delta) {
    185         int newCount = count + delta;
    186         if (newCount > buf.length) {
    187             int newLen = buf.length << 1;
    188             byte[] newBuf = new byte[newLen > newCount ? newLen : newCount];
    189             System.arraycopy(buf, 0, newBuf, 0, count);
    190             buf = newBuf;
    191         }
    192     }
    193 }
    194