/* * Copyright (C) 2015 SoftIndex LLC. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.datakernel.stream.processor; import java.io.IOException; import java.io.Reader; import java.nio.charset.Charset; /** * Reads characters from a character-input stream, buffers characters */ public final class BufferReader extends Reader { private byte[] buf; private int pos; private int limit; // region creators private BufferReader(byte[] array, int position, int length) { set(array, position, length); } /** * Creates a new instance of this object * * @param array array for buffering read characters * @param position the index of the next element to be written * @param length number of bytes which can be written to this array */ public static BufferReader create(byte[] array, int position, int length) {return new BufferReader(array, position, length);} // endregion @Override public void close() throws IOException { } public void set(byte[] array, int position, int len) { assert position >= 0 && len >= 0; this.buf = array; this.pos = position; this.limit = position + len; } /** * Returns a buffer for this object */ public byte[] array() { return buf; } /** * Returns a position for its buffer */ public int position() { return pos; } /** * Sets a position for its buffer * * @param position position to set */ public void position(int position) { assert pos >= 0; pos = position; } /** * Returns elements between the current position and the size of buffer. */ private int remaining() { return buf.length - pos; } /** * Reads a single character * * @return the character read, as an integer * @throws IOException if an I/O error occurs */ @Override public int read() throws IOException { if (pos >= limit) return -1; try { int c = buf[pos] & 0xff; if (c < 0x80) { pos++; } else if (c < 0xE0) { c = (char) ((c & 0x1F) << 6 | buf[pos + 1] & 0x3F); pos += 2; } else { c = (char) ((c & 0x0F) << 12 | (buf[pos + 1] & 0x3F) << 6 | (buf[pos + 2] & 0x3F)); pos += 3; } if (pos > limit) throw new IOException(); return c; } catch (ArrayIndexOutOfBoundsException e) { throw new IOException(e); } } /** * Reads characters into a portion of an array * * @param cbuf destination buffer * @param off offset at which to start storing characters * @param len maximum number of characters to read * @return the number of characters read, or -1 if the end of the stream has been reached * @throws IOException if an I/O error occurs */ @Override public int read(char[] cbuf, int off, int len) throws IOException { if (pos > limit) return -1; try { int i; int to = off + len; for (i = off; i < to && pos < limit; i++) { int c = buf[pos] & 0xff; if (c < 0x80) { cbuf[i] = (char) c; pos++; } else if (c < 0xE0) { cbuf[i] = (char) ((c & 0x1F) << 6 | buf[pos + 1] & 0x3F); pos += 2; } else { cbuf[i] = (char) ((c & 0x0F) << 12 | (buf[pos + 1] & 0x3F) << 6 | (buf[pos + 2] & 0x3F)); pos += 3; } } if (pos > limit) { throw new IOException(); } if (pos == limit) { pos = Integer.MAX_VALUE; } return i - off; } catch (ArrayIndexOutOfBoundsException e) { throw new IOException(e); } } @Override public String toString() { return new String(buf, pos, limit - pos, Charset.forName("UTF-8")); } }