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 021package gnu.regexp; 022import java.io.Reader; 023import java.io.BufferedReader; 024import java.io.IOException; 025 026// TODO: move(x) shouldn't rely on calling next() x times 027 028class CharIndexedReader implements CharIndexed { 029 private static final int BUFFER_INCREMENT = 1024; 030 private static final int UNKNOWN = Integer.MAX_VALUE; // value for end 031 032 private final BufferedReader br; 033 // so that we don't try to reset() right away 034 private int index = -1; 035 036 private int bufsize = BUFFER_INCREMENT; 037 038 private int end = UNKNOWN; 039 040 private char cached = OUT_OF_BOUNDS; 041 042 // Big enough for a \r\n pair 043 // lookBehind[0] = most recent 044 // lookBehind[1] = second most recent 045 private char[] lookBehind = new char[] { OUT_OF_BOUNDS, OUT_OF_BOUNDS }; 046 047 CharIndexedReader(Reader reader, int index) { 048 if (reader instanceof BufferedReader) { 049 br = (BufferedReader) reader; 050 } else { 051 br = new BufferedReader(reader,BUFFER_INCREMENT); 052 } 053 next(); 054 if (index > 0) move(index); 055 } 056 057 private boolean next() { 058 lookBehind[1] = lookBehind[0]; 059 lookBehind[0] = cached; 060 061 if (end == 1) { 062 cached = OUT_OF_BOUNDS; 063 return false; 064 } 065 end--; // closer to end 066 067 try { 068 if (index != -1) { 069 br.reset(); 070 } 071 int i = br.read(); 072 br.mark(bufsize); 073 if (i == -1) { 074 end = 1; 075 cached = OUT_OF_BOUNDS; 076 return false; 077 } 078 079 // convert the byte read into a char 080 cached = (char) i; 081 index = 1; 082 } catch (IOException e) { 083 e.printStackTrace(); 084 cached = OUT_OF_BOUNDS; 085 return false; 086 } 087 return true; 088 } 089 090 public char charAt(int index) { 091 if (index == 0) { 092 return cached; 093 } else if (index >= end) { 094 return OUT_OF_BOUNDS; 095 } else if (index >= bufsize) { 096 // Allocate more space in the buffer. 097 try { 098 while (bufsize <= index) bufsize += BUFFER_INCREMENT; 099 br.reset(); 100 br.mark(bufsize); 101 br.skip(index-1); 102 } catch (IOException e) { } 103 } else if (this.index != index) { 104 try { 105 br.reset(); 106 br.skip(index-1); 107 } catch (IOException e) { } 108 } else if (index == -1) { 109 return lookBehind[0]; 110 } else if (index == -2) { 111 return lookBehind[1]; 112 } else if (index < -2) { 113 return OUT_OF_BOUNDS; 114 } 115 116 char ch = OUT_OF_BOUNDS; 117 118 try { 119 int i = br.read(); 120 this.index = index+1; // this.index is index of next pos relative to charAt(0) 121 if (i == -1) { 122 // set flag that next should fail next time? 123 end = index; 124 return ch; 125 } 126 ch = (char) i; 127 } catch (IOException ie) { } 128 129 return ch; 130 } 131 132 public boolean move(int index) { 133 // move read position [index] clicks from 'charAt(0)' 134 boolean retval = true; 135 while (retval && (index-- > 0)) retval = next(); 136 return retval; 137 } 138 139 public boolean isValid() { 140 return (cached != OUT_OF_BOUNDS); 141 } 142}