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