001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.activemq.util;
018
019 import java.io.DataOutput;
020 import java.io.IOException;
021 import java.io.OutputStream;
022 import java.io.UTFDataFormatException;
023
024 /**
025 * Optimized ByteArrayOutputStream
026 *
027 *
028 */
029 public final class DataByteArrayOutputStream extends OutputStream implements DataOutput {
030 private static final int DEFAULT_SIZE = 2048;
031 private byte buf[];
032 private int pos;
033
034 /**
035 * Creates a new byte array output stream, with a buffer capacity of the
036 * specified size, in bytes.
037 *
038 * @param size the initial size.
039 * @exception IllegalArgumentException if size is negative.
040 */
041 public DataByteArrayOutputStream(int size) {
042 if (size < 0) {
043 throw new IllegalArgumentException("Invalid size: " + size);
044 }
045 buf = new byte[size];
046 }
047
048 /**
049 * Creates a new byte array output stream.
050 */
051 public DataByteArrayOutputStream() {
052 this(DEFAULT_SIZE);
053 }
054
055 /**
056 * start using a fresh byte array
057 *
058 * @param size
059 */
060 public void restart(int size) {
061 buf = new byte[size];
062 pos = 0;
063 }
064
065 /**
066 * start using a fresh byte array
067 */
068 public void restart() {
069 restart(DEFAULT_SIZE);
070 }
071
072 /**
073 * Get a ByteSequence from the stream
074 *
075 * @return the byte sequence
076 */
077 public ByteSequence toByteSequence() {
078 return new ByteSequence(buf, 0, pos);
079 }
080
081 /**
082 * Writes the specified byte to this byte array output stream.
083 *
084 * @param b the byte to be written.
085 */
086 public void write(int b) {
087 int newcount = pos + 1;
088 ensureEnoughBuffer(newcount);
089 buf[pos] = (byte)b;
090 pos = newcount;
091 }
092
093 /**
094 * Writes <code>len</code> bytes from the specified byte array starting at
095 * offset <code>off</code> to this byte array output stream.
096 *
097 * @param b the data.
098 * @param off the start offset in the data.
099 * @param len the number of bytes to write.
100 */
101 public void write(byte b[], int off, int len) {
102 if (len == 0) {
103 return;
104 }
105 int newcount = pos + len;
106 ensureEnoughBuffer(newcount);
107 System.arraycopy(b, off, buf, pos, len);
108 pos = newcount;
109 }
110
111 /**
112 * @return the underlying byte[] buffer
113 */
114 public byte[] getData() {
115 return buf;
116 }
117
118 /**
119 * reset the output stream
120 */
121 public void reset() {
122 pos = 0;
123 }
124
125 /**
126 * Set the current position for writing
127 *
128 * @param offset
129 */
130 public void position(int offset) {
131 ensureEnoughBuffer(offset);
132 pos = offset;
133 }
134
135 public int size() {
136 return pos;
137 }
138
139 public void writeBoolean(boolean v) {
140 ensureEnoughBuffer(pos + 1);
141 buf[pos++] = (byte)(v ? 1 : 0);
142 }
143
144 public void writeByte(int v) {
145 ensureEnoughBuffer(pos + 1);
146 buf[pos++] = (byte)(v >>> 0);
147 }
148
149 public void writeShort(int v) {
150 ensureEnoughBuffer(pos + 2);
151 buf[pos++] = (byte)(v >>> 8);
152 buf[pos++] = (byte)(v >>> 0);
153 }
154
155 public void writeChar(int v) {
156 ensureEnoughBuffer(pos + 2);
157 buf[pos++] = (byte)(v >>> 8);
158 buf[pos++] = (byte)(v >>> 0);
159 }
160
161 public void writeInt(int v) {
162 ensureEnoughBuffer(pos + 4);
163 buf[pos++] = (byte)(v >>> 24);
164 buf[pos++] = (byte)(v >>> 16);
165 buf[pos++] = (byte)(v >>> 8);
166 buf[pos++] = (byte)(v >>> 0);
167 }
168
169 public void writeLong(long v) {
170 ensureEnoughBuffer(pos + 8);
171 buf[pos++] = (byte)(v >>> 56);
172 buf[pos++] = (byte)(v >>> 48);
173 buf[pos++] = (byte)(v >>> 40);
174 buf[pos++] = (byte)(v >>> 32);
175 buf[pos++] = (byte)(v >>> 24);
176 buf[pos++] = (byte)(v >>> 16);
177 buf[pos++] = (byte)(v >>> 8);
178 buf[pos++] = (byte)(v >>> 0);
179 }
180
181 public void writeFloat(float v) throws IOException {
182 writeInt(Float.floatToIntBits(v));
183 }
184
185 public void writeDouble(double v) throws IOException {
186 writeLong(Double.doubleToLongBits(v));
187 }
188
189 public void writeBytes(String s) {
190 int length = s.length();
191 for (int i = 0; i < length; i++) {
192 write((byte)s.charAt(i));
193 }
194 }
195
196 public void writeChars(String s) {
197 int length = s.length();
198 for (int i = 0; i < length; i++) {
199 int c = s.charAt(i);
200 write((c >>> 8) & 0xFF);
201 write((c >>> 0) & 0xFF);
202 }
203 }
204
205 public void writeUTF(String str) throws IOException {
206 int strlen = str.length();
207 int encodedsize = 0;
208 int c;
209 for (int i = 0; i < strlen; i++) {
210 c = str.charAt(i);
211 if ((c >= 0x0001) && (c <= 0x007F)) {
212 encodedsize++;
213 } else if (c > 0x07FF) {
214 encodedsize += 3;
215 } else {
216 encodedsize += 2;
217 }
218 }
219 if (encodedsize > 65535) {
220 throw new UTFDataFormatException("encoded string too long: " + encodedsize + " bytes");
221 }
222 ensureEnoughBuffer(pos + encodedsize + 2);
223 writeShort(encodedsize);
224 int i = 0;
225 for (i = 0; i < strlen; i++) {
226 c = str.charAt(i);
227 if (!((c >= 0x0001) && (c <= 0x007F))) {
228 break;
229 }
230 buf[pos++] = (byte)c;
231 }
232 for (; i < strlen; i++) {
233 c = str.charAt(i);
234 if ((c >= 0x0001) && (c <= 0x007F)) {
235 buf[pos++] = (byte)c;
236 } else if (c > 0x07FF) {
237 buf[pos++] = (byte)(0xE0 | ((c >> 12) & 0x0F));
238 buf[pos++] = (byte)(0x80 | ((c >> 6) & 0x3F));
239 buf[pos++] = (byte)(0x80 | ((c >> 0) & 0x3F));
240 } else {
241 buf[pos++] = (byte)(0xC0 | ((c >> 6) & 0x1F));
242 buf[pos++] = (byte)(0x80 | ((c >> 0) & 0x3F));
243 }
244 }
245 }
246
247 private void ensureEnoughBuffer(int newcount) {
248 if (newcount > buf.length) {
249 byte newbuf[] = new byte[Math.max(buf.length << 1, newcount)];
250 System.arraycopy(buf, 0, newbuf, 0, pos);
251 buf = newbuf;
252 }
253 }
254 }