001: /*
002: * gnu/regexp/CharIndexedReader.java
003: * Copyright (C) 2001 Lee Sau Dan
004: * Based on gnu.regexp.CharIndexedInputStream by Wes Biggs
005: *
006: * This library is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU Lesser General Public License as published
008: * by the Free Software Foundation; either version 2.1 of the License, or
009: * (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
019: */
020:
021: package gnu.regexp;
022:
023: import java.io.Reader;
024: import java.io.BufferedReader;
025: import java.io.IOException;
026:
027: // TODO: move(x) shouldn't rely on calling next() x times
028:
029: class CharIndexedReader implements CharIndexed {
030: private static final int BUFFER_INCREMENT = 1024;
031: private static final int UNKNOWN = Integer.MAX_VALUE; // value for end
032:
033: private final BufferedReader br;
034: // so that we don't try to reset() right away
035: private int index = -1;
036:
037: private int bufsize = BUFFER_INCREMENT;
038:
039: private int end = UNKNOWN;
040:
041: private char cached = OUT_OF_BOUNDS;
042:
043: // Big enough for a \r\n pair
044: // lookBehind[0] = most recent
045: // lookBehind[1] = second most recent
046: private char[] lookBehind = new char[] { OUT_OF_BOUNDS,
047: OUT_OF_BOUNDS };
048:
049: CharIndexedReader(Reader reader, int index) {
050: if (reader instanceof BufferedReader) {
051: br = (BufferedReader) reader;
052: } else {
053: br = new BufferedReader(reader, BUFFER_INCREMENT);
054: }
055: next();
056: if (index > 0)
057: move(index);
058: }
059:
060: private boolean next() {
061: lookBehind[1] = lookBehind[0];
062: lookBehind[0] = cached;
063:
064: if (end == 1) {
065: cached = OUT_OF_BOUNDS;
066: return false;
067: }
068: end--; // closer to end
069:
070: try {
071: if (index != -1) {
072: br.reset();
073: }
074: int i = br.read();
075: br.mark(bufsize);
076: if (i == -1) {
077: end = 1;
078: cached = OUT_OF_BOUNDS;
079: return false;
080: }
081:
082: // convert the byte read into a char
083: cached = (char) i;
084: index = 1;
085: } catch (IOException e) {
086: e.printStackTrace();
087: cached = OUT_OF_BOUNDS;
088: return false;
089: }
090: return true;
091: }
092:
093: public char charAt(int index) {
094: if (index == 0) {
095: return cached;
096: } else if (index >= end) {
097: return OUT_OF_BOUNDS;
098: } else if (index >= bufsize) {
099: // Allocate more space in the buffer.
100: try {
101: while (bufsize <= index)
102: bufsize += BUFFER_INCREMENT;
103: br.reset();
104: br.mark(bufsize);
105: br.skip(index - 1);
106: } catch (IOException e) {
107: }
108: } else if (this .index != index) {
109: try {
110: br.reset();
111: br.skip(index - 1);
112: } catch (IOException e) {
113: }
114: } else if (index == -1) {
115: return lookBehind[0];
116: } else if (index == -2) {
117: return lookBehind[1];
118: } else if (index < -2) {
119: return OUT_OF_BOUNDS;
120: }
121:
122: char ch = OUT_OF_BOUNDS;
123:
124: try {
125: int i = br.read();
126: this .index = index + 1; // this.index is index of next pos relative to charAt(0)
127: if (i == -1) {
128: // set flag that next should fail next time?
129: end = index;
130: return ch;
131: }
132: ch = (char) i;
133: } catch (IOException ie) {
134: }
135:
136: return ch;
137: }
138:
139: public boolean move(int index) {
140: // move read position [index] clicks from 'charAt(0)'
141: boolean retval = true;
142: while (retval && (index-- > 0))
143: retval = next();
144: return retval;
145: }
146:
147: public boolean isValid() {
148: return (cached != OUT_OF_BOUNDS);
149: }
150: }
|