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.DataInput;
020    import java.io.IOException;
021    import java.io.InputStream;
022    import java.io.UTFDataFormatException;
023    
024    /**
025     * Optimized ByteArrayInputStream that can be used more than once
026     * 
027     * 
028     */
029    public final class DataByteArrayInputStream extends InputStream implements DataInput {
030        private byte[] buf;
031        private int pos;
032        private int offset;
033    
034        /**
035         * Creates a <code>StoreByteArrayInputStream</code>.
036         * 
037         * @param buf the input buffer.
038         */
039        public DataByteArrayInputStream(byte buf[]) {
040            this.buf = buf;
041            this.pos = 0;
042            this.offset = 0;
043        }
044    
045        /**
046         * Creates a <code>StoreByteArrayInputStream</code>.
047         * 
048         * @param sequence the input buffer.
049         */
050        public DataByteArrayInputStream(ByteSequence sequence) {
051            this.buf = sequence.getData();
052            this.offset = sequence.getOffset();
053            this.pos =  this.offset;
054        }
055    
056        /**
057         * Creates <code>WireByteArrayInputStream</code> with a minmalist byte
058         * array
059         */
060        public DataByteArrayInputStream() {
061            this(new byte[0]);
062        }
063    
064        /**
065         * @return the size
066         */
067        public int size() {
068            return pos - offset;
069        }
070    
071        /**
072         * @return the underlying data array
073         */
074        public byte[] getRawData() {
075            return buf;
076        }
077    
078        /**
079         * reset the <code>StoreByteArrayInputStream</code> to use an new byte
080         * array
081         * 
082         * @param newBuff
083         */
084        public void restart(byte[] newBuff) {
085            buf = newBuff;
086            pos = 0;
087        }
088    
089        /**
090         * reset the <code>StoreByteArrayInputStream</code> to use an new
091         * ByteSequence
092         * 
093         * @param sequence
094         */
095        public void restart(ByteSequence sequence) {
096            this.buf = sequence.getData();
097            this.pos = sequence.getOffset();
098        }
099    
100        /**
101         * re-start the input stream - reusing the current buffer
102         * 
103         * @param size
104         */
105        public void restart(int size) {
106            if (buf == null || buf.length < size) {
107                buf = new byte[size];
108            }
109            restart(buf);
110        }
111    
112        /**
113         * Reads the next byte of data from this input stream. The value byte is
114         * returned as an <code>int</code> in the range <code>0</code> to
115         * <code>255</code>. If no byte is available because the end of the
116         * stream has been reached, the value <code>-1</code> is returned.
117         * <p>
118         * This <code>read</code> method cannot block.
119         * 
120         * @return the next byte of data, or <code>-1</code> if the end of the
121         *         stream has been reached.
122         */
123        public int read() {
124            return (pos < buf.length) ? (buf[pos++] & 0xff) : -1;
125        }
126    
127        /**
128         * Reads up to <code>len</code> bytes of data into an array of bytes from
129         * this input stream.
130         * 
131         * @param b the buffer into which the data is read.
132         * @param off the start offset of the data.
133         * @param len the maximum number of bytes read.
134         * @return the total number of bytes read into the buffer, or
135         *         <code>-1</code> if there is no more data because the end of the
136         *         stream has been reached.
137         */
138        public int read(byte b[], int off, int len) {
139            if (b == null) {
140                throw new NullPointerException();
141            }
142            if (pos >= buf.length) {
143                return -1;
144            }
145            if (pos + len > buf.length) {
146                len = buf.length - pos;
147            }
148            if (len <= 0) {
149                return 0;
150            }
151            System.arraycopy(buf, pos, b, off, len);
152            pos += len;
153            return len;
154        }
155    
156        /**
157         * @return the number of bytes that can be read from the input stream
158         *         without blocking.
159         */
160        public int available() {
161            return buf.length - pos;
162        }
163    
164        public void readFully(byte[] b) {
165            read(b, 0, b.length);
166        }
167    
168        public void readFully(byte[] b, int off, int len) {
169            read(b, off, len);
170        }
171    
172        public int skipBytes(int n) {
173            if (pos + n > buf.length) {
174                n = buf.length - pos;
175            }
176            if (n < 0) {
177                return 0;
178            }
179            pos += n;
180            return n;
181        }
182    
183        public boolean readBoolean() {
184            return read() != 0;
185        }
186    
187        public byte readByte() {
188            return (byte)read();
189        }
190    
191        public int readUnsignedByte() {
192            return read();
193        }
194    
195        public short readShort() {
196            int ch1 = read();
197            int ch2 = read();
198            return (short)((ch1 << 8) + (ch2 << 0));
199        }
200    
201        public int readUnsignedShort() {
202            int ch1 = read();
203            int ch2 = read();
204            return (ch1 << 8) + (ch2 << 0);
205        }
206    
207        public char readChar() {
208            int ch1 = read();
209            int ch2 = read();
210            return (char)((ch1 << 8) + (ch2 << 0));
211        }
212    
213        public int readInt() {
214            int ch1 = read();
215            int ch2 = read();
216            int ch3 = read();
217            int ch4 = read();
218            return (ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0);
219        }
220    
221        public long readLong() {
222            long rc = ((long)buf[pos++] << 56) + ((long)(buf[pos++] & 255) << 48) + ((long)(buf[pos++] & 255) << 40) + ((long)(buf[pos++] & 255) << 32);
223            return rc + ((long)(buf[pos++] & 255) << 24) + ((buf[pos++] & 255) << 16) + ((buf[pos++] & 255) << 8) + ((buf[pos++] & 255) << 0);
224        }
225    
226        public float readFloat() throws IOException {
227            return Float.intBitsToFloat(readInt());
228        }
229    
230        public double readDouble() throws IOException {
231            return Double.longBitsToDouble(readLong());
232        }
233    
234        public String readLine() {
235            int start = pos;
236            while (pos < buf.length) {
237                int c = read();
238                if (c == '\n') {
239                    break;
240                }
241                if (c == '\r') {
242                    c = read();
243                    if (c != '\n' && c != -1) {
244                        pos--;
245                    }
246                    break;
247                }
248            }
249            return new String(buf, start, pos);
250        }
251    
252        public String readUTF() throws IOException {
253            int length = readUnsignedShort();
254            char[] characters = new char[length];
255            int c;
256            int c2;
257            int c3;
258            int count = 0;
259            int total = pos + length;
260            while (pos < total) {
261                c = (int)buf[pos] & 0xff;
262                if (c > 127) {
263                    break;
264                }
265                pos++;
266                characters[count++] = (char)c;
267            }
268            while (pos < total) {
269                c = (int)buf[pos] & 0xff;
270                switch (c >> 4) {
271                case 0:
272                case 1:
273                case 2:
274                case 3:
275                case 4:
276                case 5:
277                case 6:
278                case 7:
279                    pos++;
280                    characters[count++] = (char)c;
281                    break;
282                case 12:
283                case 13:
284                    pos += 2;
285                    if (pos > total) {
286                        throw new UTFDataFormatException("bad string");
287                    }
288                    c2 = (int)buf[pos - 1];
289                    if ((c2 & 0xC0) != 0x80) {
290                        throw new UTFDataFormatException("bad string");
291                    }
292                    characters[count++] = (char)(((c & 0x1F) << 6) | (c2 & 0x3F));
293                    break;
294                case 14:
295                    pos += 3;
296                    if (pos > total) {
297                        throw new UTFDataFormatException("bad string");
298                    }
299                    c2 = (int)buf[pos - 2];
300                    c3 = (int)buf[pos - 1];
301                    if (((c2 & 0xC0) != 0x80) || ((c3 & 0xC0) != 0x80)) {
302                        throw new UTFDataFormatException("bad string");
303                    }
304                    characters[count++] = (char)(((c & 0x0F) << 12) | ((c2 & 0x3F) << 6) | ((c3 & 0x3F) << 0));
305                    break;
306                default:
307                    throw new UTFDataFormatException("bad string");
308                }
309            }
310            return new String(characters, 0, count);
311        }
312    }