| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.cassandra.io.util; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.io.OutputStream; |
| import java.io.UnsupportedEncodingException; |
| import java.nio.ByteBuffer; |
| |
| import org.apache.cassandra.utils.ByteBufferUtil; |
| |
| /* |
| * This file has been modified from Apache Harmony's ByteArrayOutputStream |
| * implementation. The synchronized methods of the original have been |
| * replaced by non-synchronized methods. This makes certain operations |
| * much FASTer, but also *not thread-safe*. |
| * |
| * This file remains formatted the same as the Apache Harmony original to |
| * make patching easier if any bug fixes are made to the Harmony version. |
| */ |
| |
| /** |
| * A specialized {@link OutputStream} for class for writing content to an |
| * (internal) byte array. As bytes are written to this stream, the byte array |
| * may be expanded to hold more bytes. When the writing is considered to be |
| * finished, a copy of the byte array can be requested from the class. |
| * |
| * @see ByteArrayOutputStream |
| */ |
| public class FastByteArrayOutputStream extends OutputStream { |
| /** |
| * The byte array containing the bytes written. |
| */ |
| protected byte[] buf; |
| |
| /** |
| * The number of bytes written. |
| */ |
| protected int count; |
| |
| /** |
| * Constructs a new ByteArrayOutputStream with a default size of 32 bytes. |
| * If more than 32 bytes are written to this instance, the underlying byte |
| * array will expand. |
| */ |
| public FastByteArrayOutputStream() { |
| buf = new byte[32]; |
| } |
| |
| /** |
| * Constructs a new {@code ByteArrayOutputStream} with a default size of |
| * {@code size} bytes. If more than {@code size} bytes are written to this |
| * instance, the underlying byte array will expand. |
| * |
| * @param size |
| * initial size for the underlying byte array, must be |
| * non-negative. |
| * @throws IllegalArgumentException |
| * if {@code size} < 0. |
| */ |
| public FastByteArrayOutputStream(int size) { |
| if (size >= 0) { |
| buf = new byte[size]; |
| } else { |
| throw new IllegalArgumentException(); |
| } |
| } |
| |
| /** |
| * Closes this stream. This releases system resources used for this stream. |
| * |
| * @throws IOException |
| * if an error occurs while attempting to close this stream. |
| */ |
| @Override |
| public void close() throws IOException { |
| /** |
| * Although the spec claims "A closed stream cannot perform output |
| * operations and cannot be reopened.", this implementation must do |
| * nothing. |
| */ |
| super.close(); |
| } |
| |
| private void expand(int i) { |
| /* Can the buffer handle @i more bytes, if not expand it */ |
| if (count + i <= buf.length) { |
| return; |
| } |
| |
| long expectedExtent = (count + i) * 2L; //long to deal with possible int overflow |
| int newSize = (int) Math.min(Integer.MAX_VALUE - 8, expectedExtent); // MAX_ARRAY_SIZE |
| byte[] newbuf = new byte[newSize]; |
| System.arraycopy(buf, 0, newbuf, 0, count); |
| buf = newbuf; |
| } |
| |
| /** |
| * Resets this stream to the beginning of the underlying byte array. All |
| * subsequent writes will overwrite any bytes previously stored in this |
| * stream. |
| */ |
| public void reset() { |
| count = 0; |
| } |
| |
| /** |
| * Returns the total number of bytes written to this stream so far. |
| * |
| * @return the number of bytes written to this stream. |
| */ |
| public int size() { |
| return count; |
| } |
| |
| /** |
| * Returns the contents of this ByteArrayOutputStream as a byte array. Any |
| * changes made to the receiver after returning will not be reflected in the |
| * byte array returned to the caller. |
| * |
| * @return this stream's current contents as a byte array. |
| */ |
| public byte[] toByteArray() { |
| byte[] newArray = new byte[count]; |
| System.arraycopy(buf, 0, newArray, 0, count); |
| return newArray; |
| } |
| |
| /** |
| * Returns the contents of this ByteArrayOutputStream as a string. Any |
| * changes made to the receiver after returning will not be reflected in the |
| * string returned to the caller. |
| * |
| * @return this stream's current contents as a string. |
| */ |
| |
| @Override |
| public String toString() { |
| return new String(buf, 0, count); |
| } |
| |
| /** |
| * Returns the contents of this ByteArrayOutputStream as a string. Each byte |
| * {@code b} in this stream is converted to a character {@code c} using the |
| * following function: |
| * {@code c == (char)(((hibyte & 0xff) << 8) | (b & 0xff))}. This method is |
| * deprecated and either {@link #toString()} or {@link #toString(String)} |
| * should be used. |
| * |
| * @param hibyte |
| * the high byte of each resulting Unicode character. |
| * @return this stream's current contents as a string with the high byte set |
| * to {@code hibyte}. |
| * @deprecated Use {@link #toString()}. |
| */ |
| @Deprecated |
| public String toString(int hibyte) { |
| char[] newBuf = new char[size()]; |
| for (int i = 0; i < newBuf.length; i++) { |
| newBuf[i] = (char) (((hibyte & 0xff) << 8) | (buf[i] & 0xff)); |
| } |
| return new String(newBuf); |
| } |
| |
| /** |
| * Returns the contents of this ByteArrayOutputStream as a string converted |
| * according to the encoding declared in {@code enc}. |
| * |
| * @param enc |
| * a string representing the encoding to use when translating |
| * this stream to a string. |
| * @return this stream's current contents as an encoded string. |
| * @throws UnsupportedEncodingException |
| * if the provided encoding is not supported. |
| */ |
| public String toString(String enc) throws UnsupportedEncodingException { |
| return new String(buf, 0, count, enc); |
| } |
| |
| /** |
| * Writes {@code count} bytes from the byte array {@code buffer} starting at |
| * offset {@code index} to this stream. |
| * |
| * @param buffer |
| * the buffer to be written. |
| * @param offset |
| * the initial position in {@code buffer} to retrieve bytes. |
| * @param len |
| * the number of bytes of {@code buffer} to write. |
| * @throws NullPointerException |
| * if {@code buffer} is {@code null}. |
| * @throws IndexOutOfBoundsException |
| * if {@code offset < 0} or {@code len < 0}, or if |
| * {@code offset + len} is greater than the length of |
| * {@code buffer}. |
| */ |
| @Override |
| public void write(byte[] buffer, int offset, int len) { |
| // avoid int overflow |
| if (offset < 0 || offset > buffer.length || len < 0 |
| || len > buffer.length - offset |
| || this.count + len < 0) { |
| throw new IndexOutOfBoundsException(); |
| } |
| if (len == 0) { |
| return; |
| } |
| |
| /* Expand if necessary */ |
| expand(len); |
| System.arraycopy(buffer, offset, buf, this.count, len); |
| this.count += len; |
| } |
| |
| public void write(ByteBuffer buffer) |
| { |
| int len = buffer.remaining(); |
| expand(len); |
| ByteBufferUtil.arrayCopy(buffer, buffer.position(), buf, this.count, len); |
| this.count += len; |
| } |
| |
| /** |
| * Writes the specified byte {@code oneByte} to the OutputStream. Only the |
| * low order byte of {@code oneByte} is written. |
| * |
| * @param oneByte |
| * the byte to be written. |
| */ |
| @Override |
| public void write(int oneByte) { |
| if (count == buf.length) { |
| expand(1); |
| } |
| buf[count++] = (byte) oneByte; |
| } |
| |
| /** |
| * Takes the contents of this stream and writes it to the output stream |
| * {@code out}. |
| * |
| * @param out |
| * an OutputStream on which to write the contents of this stream. |
| * @throws IOException |
| * if an error occurs while writing to {@code out}. |
| */ |
| public void writeTo(OutputStream out) throws IOException { |
| out.write(buf, 0, count); |
| } |
| } |