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 */
017package org.apache.activemq.util;
018
019import java.io.DataInput;
020import java.io.IOException;
021import java.io.InputStream;
022import java.io.UTFDataFormatException;
023
024/**
025 * Optimized ByteArrayInputStream that can be used more than once
026 * 
027 * 
028 */
029public 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}