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