View Javadoc
1   /*
2    * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
3    * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
4    *
5    *
6    *
7    *
8    *
9    *
10   *
11   *
12   *
13   *
14   *
15   *
16   *
17   *
18   *
19   *
20   *
21   *
22   *
23   *
24   */
25  
26  package com.github.davidmoten.util;
27  
28  import java.io.IOException;
29  import java.io.OutputStream;
30  import java.io.UnsupportedEncodingException;
31  import java.util.Arrays;
32  
33  /**
34   * This class implements an output stream in which the data is written into a
35   * byte array. The buffer automatically grows as data is written to it. The data
36   * can be retrieved using <code>toByteArray()</code> and <code>toString()</code>
37   * .
38   * <p>
39   * Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in this
40   * class can be called after the stream has been closed without generating an
41   * <tt>IOException</tt>.
42   *
43   * @author Arthur van Hoff
44   * @since JDK1.0
45   */
46  
47  public class ByteArrayOutputStreamNoCopyUnsynchronized extends OutputStream {
48  
49      /**
50       * The buffer where data is stored.
51       */
52      protected byte buf[];
53  
54      /**
55       * The number of valid bytes in the buffer.
56       */
57      protected int count;
58  
59      /**
60       * Creates a new byte array output stream. The buffer capacity is initially
61       * 32 bytes, though its size increases if necessary.
62       */
63      public ByteArrayOutputStreamNoCopyUnsynchronized() {
64          this(32);
65      }
66  
67      /**
68       * Creates a new byte array output stream, with a buffer capacity of the
69       * specified size, in bytes.
70       *
71       * @param size
72       *            the initial size.
73       * @exception IllegalArgumentException
74       *                if size is negative.
75       */
76      public ByteArrayOutputStreamNoCopyUnsynchronized(int size) {
77          if (size < 0) {
78              throw new IllegalArgumentException("Negative initial size: " + size);
79          }
80          buf = new byte[size];
81      }
82  
83      /**
84       * Increases the capacity if necessary to ensure that it can hold at least
85       * the number of elements specified by the minimum capacity argument.
86       *
87       * @param minCapacity
88       *            the desired minimum capacity
89       * @throws OutOfMemoryError
90       *             if {@code minCapacity < 0}. This is interpreted as a request
91       *             for the unsatisfiably large capacity
92       *             {@code (long) Integer.MAX_VALUE + (minCapacity - Integer.MAX_VALUE)}
93       *             .
94       */
95      private void ensureCapacity(int minCapacity) {
96          // overflow-conscious code
97          if (minCapacity - buf.length > 0)
98              grow(minCapacity);
99      }
100 
101     /**
102      * The maximum size of array to allocate. Some VMs reserve some header words
103      * in an array. Attempts to allocate larger arrays may result in
104      * OutOfMemoryError: Requested array size exceeds VM limit
105      */
106     private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
107 
108     /**
109      * Increases the capacity to ensure that it can hold at least the number of
110      * elements specified by the minimum capacity argument.
111      *
112      * @param minCapacity
113      *            the desired minimum capacity
114      */
115     private void grow(int minCapacity) {
116         // overflow-conscious code
117         int oldCapacity = buf.length;
118         int newCapacity = oldCapacity << 1;
119         if (newCapacity - minCapacity < 0)
120             newCapacity = minCapacity;
121         if (newCapacity - MAX_ARRAY_SIZE > 0)
122             newCapacity = hugeCapacity(minCapacity);
123         buf = Arrays.copyOf(buf, newCapacity);
124     }
125 
126     private static int hugeCapacity(int minCapacity) {
127         if (minCapacity < 0) // overflow
128             throw new OutOfMemoryError();
129         return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
130     }
131 
132     /**
133      * Writes the specified byte to this byte array output stream.
134      *
135      * @param b
136      *            the byte to be written.
137      */
138     @Override
139     public void write(int b) {
140         ensureCapacity(count + 1);
141         buf[count] = (byte) b;
142         count += 1;
143     }
144 
145     /**
146      * Writes <code>len</code> bytes from the specified byte array starting at
147      * offset <code>off</code> to this byte array output stream.
148      *
149      * @param b
150      *            the data.
151      * @param off
152      *            the start offset in the data.
153      * @param len
154      *            the number of bytes to write.
155      */
156     @Override
157     public void write(byte b[], int off, int len) {
158         if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) - b.length > 0)) {
159             throw new IndexOutOfBoundsException();
160         }
161         ensureCapacity(count + len);
162         System.arraycopy(b, off, buf, count, len);
163         count += len;
164     }
165 
166     /**
167      * Writes the complete contents of this byte array output stream to the
168      * specified output stream argument, as if by calling the output stream's
169      * write method using <code>out.write(buf, 0, count)</code>.
170      *
171      * @param out
172      *            the output stream to which to write the data.
173      * @exception IOException
174      *                if an I/O error occurs.
175      */
176     public void writeTo(OutputStream out) throws IOException {
177         out.write(buf, 0, count);
178     }
179 
180     /**
181      * Resets the <code>count</code> field of this byte array output stream to
182      * zero, so that all currently accumulated output in the output stream is
183      * discarded. The output stream can be used again, reusing the already
184      * allocated buffer space.
185      *
186      * @see java.io.ByteArrayInputStream#reset()
187      */
188     public void reset() {
189         count = 0;
190     }
191 
192     /**
193      * Creates a newly allocated byte array. Its size is the current size of
194      * this output stream and the valid contents of the buffer have been copied
195      * into it.
196      *
197      * @return the current contents of this output stream, as a byte array.
198      * @see java.io.ByteArrayOutputStream#size()
199      */
200     public byte toByteArray()[] {
201         return Arrays.copyOf(buf, count);
202     }
203 
204     public byte[] toByteArrayNoCopy() {
205         return buf;
206     }
207 
208     /**
209      * Returns the current size of the buffer.
210      *
211      * @return the value of the <code>count</code> field, which is the number of
212      *         valid bytes in this output stream.
213      * @see java.io.ByteArrayOutputStream#size()
214      */
215     public int size() {
216         return count;
217     }
218 
219     /**
220      * Converts the buffer's contents into a string decoding bytes using the
221      * platform's default character set. The length of the new <tt>String</tt>
222      * is a function of the character set, and hence may not be equal to the
223      * size of the buffer.
224      *
225      * <p>
226      * This method always replaces malformed-input and unmappable-character
227      * sequences with the default replacement string for the platform's default
228      * character set. The {@linkplain java.nio.charset.CharsetDecoder} class
229      * should be used when more control over the decoding process is required.
230      *
231      * @return String decoded from the buffer's contents.
232      * @since JDK1.1
233      */
234     @Override
235     public String toString() {
236         return new String(buf, 0, count);
237     }
238 
239     /**
240      * Converts the buffer's contents into a string by decoding the bytes using
241      * the named {@link java.nio.charset.Charset charset}. The length of the new
242      * <tt>String</tt> is a function of the charset, and hence may not be equal
243      * to the length of the byte array.
244      *
245      * <p>
246      * This method always replaces malformed-input and unmappable-character
247      * sequences with this charset's default replacement string. The
248      * {@link java.nio.charset.CharsetDecoder} class should be used when more
249      * control over the decoding process is required.
250      *
251      * @param charsetName
252      *            the name of a supported {@link java.nio.charset.Charset
253      *            charset}
254      * @return String decoded from the buffer's contents.
255      * @exception UnsupportedEncodingException
256      *                If the named charset is not supported
257      * @since JDK1.1
258      */
259     public String toString(String charsetName) throws UnsupportedEncodingException {
260         return new String(buf, 0, count, charsetName);
261     }
262 
263     /**
264      * Creates a newly allocated string. Its size is the current size of the
265      * output stream and the valid contents of the buffer have been copied into
266      * it. Each character <i>c</i> in the resulting string is constructed from
267      * the corresponding element <i>b</i> in the byte array such that:
268      * <blockquote>
269      * 
270      * <pre>
271      * c == (char) (((hibyte &amp; 0xff) &lt;&lt; 8) | (b &amp; 0xff))
272      * </pre>
273      * 
274      * </blockquote>
275      *
276      * @deprecated This method does not properly convert bytes into characters.
277      *             As of JDK&nbsp;1.1, the preferred way to do this is via the
278      *             <code>toString(String enc)</code> method, which takes an
279      *             encoding-name argument, or the <code>toString()</code>
280      *             method, which uses the platform's default character encoding.
281      *
282      * @param hibyte
283      *            the high byte of each resulting Unicode character.
284      * @return the current contents of the output stream, as a string.
285      * @see java.io.ByteArrayOutputStream#size()
286      * @see java.io.ByteArrayOutputStream#toString(String)
287      * @see java.io.ByteArrayOutputStream#toString()
288      */
289     @Deprecated
290     public String toString(int hibyte) {
291         return new String(buf, hibyte, 0, count);
292     }
293 
294     /**
295      * Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in
296      * this class can be called after the stream has been closed without
297      * generating an <tt>IOException</tt>.
298      */
299     @Override
300     public void close() throws IOException {
301     }
302 
303 }