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