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