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    }