1 /*
   2  * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.tools.javac.util;
  27 
  28 import java.io.*;
  29 
  30 /** A byte buffer is a flexible array which grows when elements are
  31  *  appended. There are also methods to append names to byte buffers
  32  *  and to convert byte buffers to names.
  33  *
  34  *  <p><b>This is NOT part of any supported API.
  35  *  If you write code that depends on this, you do so at your own risk.
  36  *  This code and its internal interfaces are subject to change or
  37  *  deletion without notice.</b>
  38  */
  39 public class ByteBuffer {
  40 
  41     /** An array holding the bytes in this buffer; can be grown.
  42      */
  43     public byte[] elems;
  44 
  45     /** The current number of defined bytes in this buffer.
  46      */
  47     public int length;
  48 
  49     /** Create a new byte buffer.
  50      */
  51     public ByteBuffer() {
  52         this(64);
  53     }
  54 
  55     /** Create a new byte buffer with an initial elements array
  56      *  of given size.
  57      */
  58     public ByteBuffer(int initialSize) {
  59         elems = new byte[initialSize];
  60         length = 0;
  61     }
  62 
  63     /** Append byte to this buffer.
  64      */
  65     public void appendByte(int b) {
  66         elems = ArrayUtils.ensureCapacity(elems, length);
  67         elems[length++] = (byte)b;
  68     }
  69 
  70     /** Append `len' bytes from byte array,
  71      *  starting at given `start' offset.
  72      */
  73     public void appendBytes(byte[] bs, int start, int len) {
  74         elems = ArrayUtils.ensureCapacity(elems, length + len);
  75         System.arraycopy(bs, start, elems, length, len);
  76         length += len;
  77     }
  78 
  79     /** Append all bytes from given byte array.
  80      */
  81     public void appendBytes(byte[] bs) {
  82         appendBytes(bs, 0, bs.length);
  83     }
  84 
  85     /** Append a character as a two byte number.
  86      */
  87     public void appendChar(int x) {
  88         elems = ArrayUtils.ensureCapacity(elems, length + 1);
  89         elems[length  ] = (byte)((x >>  8) & 0xFF);
  90         elems[length+1] = (byte)((x      ) & 0xFF);
  91         length = length + 2;
  92     }
  93 
  94     /** Append an integer as a four byte number.
  95      */
  96     public void appendInt(int x) {
  97         elems = ArrayUtils.ensureCapacity(elems, length + 3);
  98         elems[length  ] = (byte)((x >> 24) & 0xFF);
  99         elems[length+1] = (byte)((x >> 16) & 0xFF);
 100         elems[length+2] = (byte)((x >>  8) & 0xFF);
 101         elems[length+3] = (byte)((x      ) & 0xFF);
 102         length = length + 4;
 103     }
 104 
 105     /** Append a long as an eight byte number.
 106      */
 107     public void appendLong(long x) {
 108         ByteArrayOutputStream buffer = new ByteArrayOutputStream(8);
 109         DataOutputStream bufout = new DataOutputStream(buffer);
 110         try {
 111             bufout.writeLong(x);
 112             appendBytes(buffer.toByteArray(), 0, 8);
 113         } catch (IOException e) {
 114             throw new AssertionError("write");
 115         }
 116     }
 117 
 118     /** Append a float as a four byte number.
 119      */
 120     public void appendFloat(float x) {
 121         ByteArrayOutputStream buffer = new ByteArrayOutputStream(4);
 122         DataOutputStream bufout = new DataOutputStream(buffer);
 123         try {
 124             bufout.writeFloat(x);
 125             appendBytes(buffer.toByteArray(), 0, 4);
 126         } catch (IOException e) {
 127             throw new AssertionError("write");
 128         }
 129     }
 130 
 131     /** Append a double as a eight byte number.
 132      */
 133     public void appendDouble(double x) {
 134         ByteArrayOutputStream buffer = new ByteArrayOutputStream(8);
 135         DataOutputStream bufout = new DataOutputStream(buffer);
 136         try {
 137             bufout.writeDouble(x);
 138             appendBytes(buffer.toByteArray(), 0, 8);
 139         } catch (IOException e) {
 140             throw new AssertionError("write");
 141         }
 142     }
 143 
 144     /** Append a name.
 145      */
 146     public void appendName(Name name) {
 147         appendBytes(name.getByteArray(), name.getByteOffset(), name.getByteLength());
 148     }
 149 
 150      /** Append the content of a given input stream.
 151      */
 152     public void appendStream(InputStream is) throws IOException {
 153         try {
 154             int start = length;
 155             int initialSize = is.available();
 156             elems = ArrayUtils.ensureCapacity(elems, length + initialSize);
 157             int r = is.read(elems, start, initialSize);
 158             int bp = start;
 159             while (r != -1) {
 160                 bp += r;
 161                 elems = ArrayUtils.ensureCapacity(elems, bp);
 162                 r = is.read(elems, bp, elems.length - bp);
 163             }
 164         } finally {
 165             try {
 166                 is.close();
 167             } catch (IOException e) {
 168                 /* Ignore any errors, as this stream may have already
 169                  * thrown a related exception which is the one that
 170                  * should be reported.
 171                  */
 172             }
 173         }
 174     }
 175 
 176     /** Extract an integer at position bp from elems.
 177      */
 178     public int getInt(int bp) {
 179         return
 180             ((elems[bp] & 0xFF) << 24) +
 181             ((elems[bp+1] & 0xFF) << 16) +
 182             ((elems[bp+2] & 0xFF) << 8) +
 183             (elems[bp+3] & 0xFF);
 184     }
 185 
 186 
 187     /** Extract a long integer at position bp from elems.
 188      */
 189     public long getLong(int bp) {
 190         DataInputStream elemsin =
 191             new DataInputStream(new ByteArrayInputStream(elems, bp, 8));
 192         try {
 193             return elemsin.readLong();
 194         } catch (IOException e) {
 195             throw new AssertionError(e);
 196         }
 197     }
 198 
 199     /** Extract a float at position bp from elems.
 200      */
 201     public float getFloat(int bp) {
 202         DataInputStream elemsin =
 203             new DataInputStream(new ByteArrayInputStream(elems, bp, 4));
 204         try {
 205             return elemsin.readFloat();
 206         } catch (IOException e) {
 207             throw new AssertionError(e);
 208         }
 209     }
 210 
 211     /** Extract a double at position bp from elems.
 212      */
 213     public double getDouble(int bp) {
 214         DataInputStream elemsin =
 215             new DataInputStream(new ByteArrayInputStream(elems, bp, 8));
 216         try {
 217             return elemsin.readDouble();
 218         } catch (IOException e) {
 219             throw new AssertionError(e);
 220         }
 221     }
 222 
 223     /** Extract a character at position bp from elems.
 224      */
 225     public char getChar(int bp) {
 226         return
 227             (char)(((elems[bp] & 0xFF) << 8) + (elems[bp+1] & 0xFF));
 228     }
 229 
 230     public byte getByte(int bp) {
 231         return elems[bp];
 232     }
 233 
 234     /** Reset to zero length.
 235      */
 236     public void reset() {
 237         length = 0;
 238     }
 239 
 240     /** Convert contents to name.
 241      */
 242     public Name toName(Names names) {
 243         return names.fromUtf(elems, 0, length);
 244     }
 245 }