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 }