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