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 & 0xff) << 8) | (b & 0xff))
272 * </pre>
273 *
274 * </blockquote>
275 *
276 * @deprecated This method does not properly convert bytes into characters.
277 * As of JDK 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 }