package com.mozz.htmlnative.reader; import android.support.annotation.NonNull; import android.util.Log; import com.mozz.htmlnative.utils.IOUtils; import java.io.EOFException; import java.io.IOException; import java.io.Reader; public class StreamReader implements TextReader { private static final String TAG = StreamReader.class.getSimpleName(); public static final int CACHE_SIZE = 1024 * 2; @NonNull private char[] temp = new char[CACHE_SIZE]; private int tempPos = -1; private int tempCount = 0; private int column = 1; private int line = 1; private char ch = ' '; private Reader mInputStream; boolean meetEof = false; private long countOfRead = 0; public StreamReader() { } public StreamReader(Reader inputStream) { mInputStream = inputStream; } protected void setInputStream(Reader inputStream) { mInputStream = inputStream; } @Override public char nextCh() throws EOFException { try { if (tempPos == tempCount - 1) { if (meetEof) { throw new EOFException("Reach the end of stream!"); } fillInCache(); } ch = temp[tempPos + 1]; tempPos++; column++; if (ch == '\n' || ch == '\r') { this.line++; column = 1; } countOfRead++; return ch; } catch (IOException e) { close(); if (e instanceof EOFException) { throw (EOFException) e; } EOFException eofException = new EOFException(); eofException.initCause(e); throw eofException; } } private void fillInCache() throws IOException { if (mInputStream == null) { Log.w(TAG, "input stream is null"); throw new EOFException("input stream is null"); } int count = mInputStream.read(temp); if (count == -1) { // If reach the end of stream, will add an ' ' to the end of the stream for lexer to // handle, then on the next round of nextCh(), an EOFException will be thrown. temp[0] = ' '; tempCount = 1; tempPos = -1; meetEof = true; return; } tempCount = count; tempPos = -1; } @Override public long line() { return line; } @Override public long column() { return column; } @Override public char current() { return ch; } @Override public void close() { IOUtils.closeQuietly(mInputStream); } @Override public long countOfRead() { return countOfRead; } }