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