Source code: org/apache/axis/utils/ByteArrayOutputStream.java
1 /*
2 * Copyright 2003,2004 The Apache Software Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.axis.utils;
18
19 import java.io.IOException;
20 import java.io.OutputStream;
21 import java.io.UnsupportedEncodingException;
22 import java.util.List;
23
24 /**
25 * This class implements an output stream in which the data is
26 * written into a byte array. The buffer automatically grows as data
27 * is written to it.
28 * <p/>
29 * The data can be retrieved using <code>toByteArray()</code> and
30 * <code>toString()</code>.
31 * <p/>
32 * Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in
33 * this class can be called after the stream has been closed without
34 * generating an <tt>IOException</tt>.
35 * <p/>
36 * This is an alternative implementation of the java.io.ByteArrayOutputStream
37 * class. The original implementation only allocates 32 bytes at the beginning.
38 * As this class is designed for heavy duty it starts at 1024 bytes. In contrast
39 * to the original it doesn't reallocate the whole memory block but allocates
40 * additional buffers. This way no buffers need to be garbage collected and
41 * the contents don't have to be copied to the new buffer. This class is
42 * designed to behave exactly like the original. The only exception is the
43 * deprecated toString(int) method that has been ignored.
44 *
45 * @author <a href="mailto:jeremias@apache.org">Jeremias Maerki</a>
46 */
47 public class ByteArrayOutputStream extends OutputStream {
48
49 private List buffers = new java.util.ArrayList();
50 private int currentBufferIndex;
51 private int filledBufferSum;
52 private byte[] currentBuffer;
53 private int count;
54
55 /**
56 * Creates a new byte array output stream. The buffer capacity is
57 * initially 1024 bytes, though its size increases if necessary.
58 */
59 public ByteArrayOutputStream() {
60 this(1024);
61 }
62
63 /**
64 * Creates a new byte array output stream, with a buffer capacity of
65 * the specified size, in bytes.
66 *
67 * @param size the initial size.
68 * @throws IllegalArgumentException if size is negative.
69 */
70 public ByteArrayOutputStream(int size) {
71 if (size < 0) {
72 throw new IllegalArgumentException(
73 Messages.getMessage("illegalArgumentException01",
74 Integer.toString(size)));
75 }
76 needNewBuffer(size);
77 }
78
79 private byte[] getBuffer(int index) {
80 return (byte[]) buffers.get(index);
81 }
82
83 private void needNewBuffer(int newcount) {
84 if (currentBufferIndex < buffers.size() - 1) {
85 //Recycling old buffer
86 filledBufferSum += currentBuffer.length;
87 currentBufferIndex++;
88 currentBuffer = getBuffer(currentBufferIndex);
89 } else {
90 //Creating new buffer
91 int newBufferSize;
92 if (currentBuffer == null) {
93 newBufferSize = newcount;
94 filledBufferSum = 0;
95 } else {
96 newBufferSize = Math.max(currentBuffer.length << 1,
97 newcount - filledBufferSum);
98 filledBufferSum += currentBuffer.length;
99 }
100 currentBufferIndex++;
101 currentBuffer = new byte[newBufferSize];
102 buffers.add(currentBuffer);
103 }
104 }
105
106 /**
107 * @see java.io.OutputStream#write(byte[], int, int)
108 */
109 public synchronized void write(byte[] b, int off, int len) {
110 if ((off < 0)
111 || (off > b.length)
112 || (len < 0)
113 || ((off + len) > b.length)
114 || ((off + len) < 0)) {
115 throw new IndexOutOfBoundsException(
116 Messages.getMessage("indexOutOfBoundsException00"));
117 } else if (len == 0) {
118 return;
119 }
120 int newcount = count + len;
121 int remaining = len;
122 int inBufferPos = count - filledBufferSum;
123 while (remaining > 0) {
124 int part = Math.min(remaining, currentBuffer.length - inBufferPos);
125 System.arraycopy(b, off + len - remaining, currentBuffer,
126 inBufferPos, part);
127 remaining -= part;
128 if (remaining > 0) {
129 needNewBuffer(newcount);
130 inBufferPos = 0;
131 }
132 }
133 count = newcount;
134 }
135
136 /**
137 * Calls the write(byte[]) method.
138 *
139 * @see java.io.OutputStream#write(int)
140 */
141 public synchronized void write(int b) {
142 write(new byte[]{(byte) b}, 0, 1);
143 }
144
145 /**
146 * @see java.io.ByteArrayOutputStream#size()
147 */
148 public int size() {
149 return count;
150 }
151
152 /**
153 * Closing a <tt>ByteArrayOutputStream</tt> has no effect. The methods in
154 * this class can be called after the stream has been closed without
155 * generating an <tt>IOException</tt>.
156 *
157 * @throws IOException in case an I/O error occurs
158 */
159 public void close() throws IOException {
160 //nop
161 }
162
163 /**
164 * @see java.io.ByteArrayOutputStream#reset()
165 */
166 public synchronized void reset() {
167 count = 0;
168 filledBufferSum = 0;
169 currentBufferIndex = 0;
170 currentBuffer = getBuffer(currentBufferIndex);
171 }
172
173 /**
174 * @see java.io.ByteArrayOutputStream#writeTo(OutputStream)
175 */
176 public synchronized void writeTo(OutputStream out) throws IOException {
177 int remaining = count;
178 for (int i = 0; i < buffers.size(); i++) {
179 byte[] buf = getBuffer(i);
180 int c = Math.min(buf.length, remaining);
181 out.write(buf, 0, c);
182 remaining -= c;
183 if (remaining == 0) {
184 break;
185 }
186 }
187 }
188
189 /**
190 * @see java.io.ByteArrayOutputStream#toByteArray()
191 */
192 public synchronized byte toByteArray()[] {
193 int remaining = count;
194 int pos = 0;
195 byte newbuf[] = new byte[count];
196 for (int i = 0; i < buffers.size(); i++) {
197 byte[] buf = getBuffer(i);
198 int c = Math.min(buf.length, remaining);
199 System.arraycopy(buf, 0, newbuf, pos, c);
200 pos += c;
201 remaining -= c;
202 if (remaining == 0) {
203 break;
204 }
205 }
206 return newbuf;
207 }
208
209 /**
210 * @see java.io.ByteArrayOutputStream#toString()
211 */
212 public String toString() {
213 return new String(toByteArray());
214 }
215
216 /**
217 * @see java.io.ByteArrayOutputStream#toString(String)
218 */
219 public String toString(String enc) throws UnsupportedEncodingException {
220 return new String(toByteArray(), enc);
221 }
222
223 }