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 }